home *** CD-ROM | disk | FTP | other *** search
/ Super Shareware Collection / Super Shareware Collection.iso / os_2 / clisp.zip / COMPILER.LSP < prev    next >
Lisp/Scheme  |  1994-02-05  |  538KB  |  12,100 lines

  1. ; CLISP - Compiler
  2. ; Bruno Haible 20.-30.09.1988, 05.-07.10.1988, 10.10.1988, 16.12.1988
  3. ;   Version für KCL 27.06.1989, 05.-07.07.1989
  4. ;   c-VALUES erweitert am 14.07.1989
  5. ;   label-operand in assemble-LAP korrigiert am 14.07.1989
  6. ;   ANODE-Komponenten SOURCE, STACKZ eliminiert am 14.07.1989
  7. ;     (konditionell von #+COMPILER-DEBUG abhängig)
  8. ;   Peephole-Optimierung-Protokoll konditionell von #+PEEPHOLE-DEBUG abhängig
  9. ;   Version für CLISP 28.07.1989-11.08.1989
  10. ;   Variablen-Optimierungen 10.03.1991
  11. ; Michael Stoll, September-Dezember 1991:
  12. ;   - Bytecode überarbeitet
  13. ;   - Code-Optimierung bzgl. Labels/Sprüngen verbessert
  14. ;   - kleine Verbesserung bei c-plus/c-minus,
  15. ;     Compilation von CxxxR in Folge von (CAR) und (CDR)
  16. ;   - SUBR-Aufrufe ohne Argument-Check zur Laufzeit,
  17. ;     SUBRs als Konstanten (via #.#'name)
  18. ;   - Aufrufe lokaler Funktionen ohne Argument-Check zur Laufzeit
  19. ;   - Rekursive Aufrufe durch Unterprogrammaufruf JSR, bei Endrekursion
  20. ;     JMPTAIL (entspricht PSETQ mit anschließendem Sprung)
  21. ;   - Verbesserung bei Aufruf einer Funktion mit Rest-Parametern via APPLY
  22. ; Bruno Haible, Februar-März 1992:
  23. ;   - detailliertere seclass, besseres PSETQ
  24. ;   - besseres Constant Folding
  25. ;   - Cross-Compilation
  26. ; Bruno Haible, 03.06.1992:
  27. ;   - Inline-Compilation von Aufrufen globaler Funktionen
  28. ; Bruno Haible, August 1993:
  29. ;   - Unterstützung für CLOS: generische Funktionen %GENERIC-FUNCTION-LAMBDA,
  30. ;     Optimierung unbenutzter Required-Parameter %OPTIMIZE-FUNCTION-LAMBDA
  31. ;   - GENERIC-FLET, GENERIC-LABELS
  32. ;   - Inline-Compilation von (APPLY (FUNCTION ...) ...)
  33. ; Weitere Vorhaben:
  34. ;   - Variablen-Environments so verändern, daß Aufruf von lokalen Funktionen
  35. ;     mittels JSR/JMPTAIL möglich wird (d.h. nachträgliche Entscheidung, ob
  36. ;     Aufruf durch CALLC oder JSR)
  37. ;   - evtl. bessere Optimierung durch Datenflußanalyse
  38. ;   - Inline-Compilation von Aufrufen lokaler Funktionen
  39.  
  40. ; Zur Cross-Compilation (wahlweise mit #+CLISP oder #-CLISP):
  41. ; CROSS, die Sprache und den Maschinenbezeichner in die Liste *features*
  42. ; aufnehmen, andere Maschinenbezeichner aus *features* herausnehmen.
  43. ; Dann den Compiler laden (evtl. compilieren und laden).
  44. ; Dann CROSS wieder aus der Liste *features* herausnehmen, und
  45. ; mit (cross:compile-file ...) Files compilieren.
  46.  
  47. ; #-CROSS impliziert #+CLISP.
  48.  
  49. #-CROSS (in-package "LISP")
  50. #-CROSS (export '(compiler compile compile-file disassemble))
  51. #-CROSS (pushnew 'compiler *features*)
  52.  
  53. #-CROSS (in-package "COMPILER")
  54. #+CROSS (in-package "CROSS" :nicknames '("CLISP"))
  55. #-CLISP '#.(progn #-(or DEUTSCH ENGLISH FRANCAIS) (pushnew 'ENGLISH *features*))
  56. ;; Konvention: Schreibe SYSTEM::PNAME für ein Symbol, das "zufällig" in
  57. ;; #<PACKAGE SYSTEM> sitzt, wir das Symbol aber nicht weiter benutzen.
  58. ;; Schreibe SYS::PNAME, wenn wir von dem Symbol irgendwelche Eigenschaften
  59. ;; voraussetzen. Schreibe COMPILER::PNAME, wenn der Compiler das Symbol
  60. ;; deklariert und es von anderen Programmteilen benutzt wird.
  61. #+CLISP (import '(sys::function-name-p sys::parse-body sys::make-load-time-eval
  62.                   sys::closure-name sys::closure-codevec sys::closure-consts
  63.                   sys::fixnump sys::short-float-p sys::single-float-p
  64.                   sys::double-float-p sys::long-float-p
  65.                   sys::search-file sys::*date-format*
  66.                   sys::%funtabref sys::inlinable
  67.                   sys::*compiling* sys::*compiling-from-file* sys::*inline-functions*
  68.                   sys::*venv* sys::*fenv* sys::*benv* sys::*genv* sys::*denv*
  69.                   sys::*toplevel-denv*
  70.                   COMPILER::C-PROCLAIM COMPILER::C-PROCLAIM-CONSTANT
  71.                   COMPILER::C-DEFUN COMPILER::C-PROVIDE COMPILER::C-REQUIRE
  72.         )        )
  73. #-CROSS (import '(sys::version sys::subr-info))
  74.  
  75. #+CROSS (shadow '(compile-file))
  76. #+CROSS (export '(compile-file))
  77.  
  78. #-CLISP (shadow '(macroexpand-1 macroexpand))
  79. #-CLISP
  80. (progn
  81.   (defun function-name-p (form)
  82.     (or (symbolp form)
  83.         (and (consp form) (eq (car form) 'SETF)
  84.              (consp (setq form (cdr form))) (null (cdr form))
  85.              (symbolp (car form))
  86.   ) )   )
  87.   (defun macroexpand-1 (form &optional (env (vector nil nil)))
  88.     (if (and (consp form) (symbolp (car form)))
  89.       (multiple-value-bind (a b c) (fenv-search (car form) (svref env 1))
  90.         (declare (ignore c))
  91.         (cond ((eq a 'system::macro) (values (funcall b form env) t))
  92.               ((macro-function (car form))
  93.                (values (funcall (macro-function (car form)) form env) t)
  94.               )
  95.               (t (values form nil))
  96.       ) )
  97.       (if (symbolp form)
  98.         (let ((h (venv-search-macro form (svref env 0))))
  99.           (if (symbol-macro-p h)
  100.             (values (sys::%record-ref h 0) t)
  101.             (values form nil)
  102.         ) )
  103.         (values form nil)
  104.   ) ) )
  105.   (defun macroexpand (form &optional (env (vector nil nil)))
  106.     (multiple-value-bind (a b) (macroexpand-1 form env)
  107.       (if b
  108.         (loop
  109.           (multiple-value-setq (a b) (macroexpand-1 a env))
  110.           (unless b (return (values a t)))
  111.         )
  112.         (values form nil)
  113.   ) ) )
  114.   (defun parse-body (body &optional docstring-allowed env)
  115.     (do ((bodyr body (cdr bodyr))
  116.          (declarations nil)
  117.          (docstring nil)
  118.          (form nil))
  119.         ((null bodyr) (values bodyr declarations docstring))
  120.       (cond ((and (stringp (car bodyr)) (cdr bodyr) (null docstring) docstring-allowed)
  121.              (setq docstring (car bodyr))
  122.             )
  123.             ((not (listp (setq form (macroexpand (car bodyr) env))))
  124.              (return (values bodyr declarations docstring))
  125.             )
  126.             ((eq (car form) 'DECLARE)
  127.              (dolist (decl (cdr form)) (push decl declarations))
  128.             )
  129.             (t (return (values bodyr declarations docstring)))
  130.   ) ) )
  131.   (defstruct (load-time-eval
  132.               (:print-function
  133.                 (lambda (object stream depth)
  134.                   (declare (ignore depth))
  135.                   (write-string "#." stream)
  136.                   (write (load-time-eval-form object) :stream stream)
  137.               ) )
  138.               (:constructor make-load-time-eval (form))
  139.              )
  140.     form
  141.   )
  142.   (defun fixnump (object) (typep object 'FIXNUM))
  143.   (defun short-float-p (object) (typep object 'SHORT-FLOAT))
  144.   (defun single-float-p (object) (typep object 'SINGLE-FLOAT))
  145.   (defun double-float-p (object) (typep object 'DOUBLE-FLOAT))
  146.   (defun long-float-p (object) (typep object 'LONG-FLOAT))
  147.   ; Sucht ein Programm-File. Siehe INIT.LSP :
  148.   (defun search-file (filename extensions
  149.                       &aux (use-extensions (null (pathname-type filename))) )
  150.     (when use-extensions
  151.       (setq extensions ; Case-Konversionen auf den Extensions durchführen
  152.         (mapcar #'pathname-type extensions)
  153.     ) )
  154.     ; Defaults einmergen:
  155.     (setq filename (merge-pathnames filename '#".*"))
  156.     ; Suchen:
  157.     (let ((already-searched nil))
  158.       (dolist (dir (cons '#"" '()))
  159.         (let ((search-filename
  160.                 (merge-pathnames (merge-pathnames filename dir))
  161.              ))
  162.           (unless (member search-filename already-searched :test #'equal)
  163.             (let ((xpathnames (directory search-filename :full t)))
  164.               (when use-extensions
  165.                 ; nach passenden Extensions filtern:
  166.                 (setq xpathnames
  167.                   (delete-if-not ; hat xpathname eine der gegebenen Extensions?
  168.                     #'(lambda (xpathname)
  169.                         (member (pathname-type (first xpathname)) extensions
  170.                                 :test #'string=
  171.                       ) )
  172.                     xpathnames
  173.               ) ) )
  174.               (when xpathnames
  175.                 ; nach Datum sortiert, zurückgeben:
  176.                 (dolist (xpathname xpathnames)
  177.                   (setf (rest xpathname)
  178.                         (apply #'encode-universal-time (third xpathname))
  179.                 ) )
  180.                 (return (mapcar #'first (sort xpathnames #'> :key #'rest)))
  181.             ) )
  182.             (push search-filename already-searched)
  183.       ) ) )
  184.   ) )
  185.   (defun make-macro-expander (macrodef)
  186.     (let ((dummysym (make-symbol (symbol-name (car macrodef)))))
  187.       (eval `(DEFMACRO ,dummysym ,@(cdr macrodef)))
  188.       #'(lambda (form &rest env)
  189.           (apply #'lisp:macroexpand-1 (cons dummysym (cdr form)) env)
  190.         )
  191.   ) )
  192.   ; siehe DEFS1.LSP :
  193.   (defconstant *date-format*
  194.     #+DEUTSCH "~1{~3@*~D.~4@*~D.~5@*~D ~2@*~2,'0D:~1@*~2,'0D:~0@*~2,'0D~:}"
  195.     #+ENGLISH "~1{~5@*~D/~4@*~D/~3@*~D ~2@*~2,'0D.~1@*~2,'0D.~0@*~2,'0D~:}"
  196.   )
  197. )
  198.  
  199.  
  200. ; Version des Evaluators:
  201. ; CLISP1 : Assembler-Version
  202. ; CLISP2 : C-Version mit SP-Manipulierbarkeit
  203. ; CLISP3 : C-Version ohne SP-Manipulierbarkeit
  204. #+(and CROSS (not (or CLISP1 CLISP2 CLISP3)))
  205. (eval-when (eval load compile)
  206.   (pushnew
  207.     (if (y-or-n-p #+DEUTSCH "Die C-Version?"
  208.                   #+ENGLISH "The C version?"
  209.         )
  210.       (if (y-or-n-p #+DEUTSCH "Kann man von C aus den SP verändern?"
  211.                     #+ENGLISH "Can C manipulate the SP stack pointer?"
  212.           )
  213.         'CLISP2
  214.         'CLISP3
  215.       )
  216.       'CLISP1
  217.     )
  218.     *features*
  219. ) )
  220. #+CLISP1 (defconstant *jmpbuf-size* 1)
  221. #+(and CROSS (not CLISP1))
  222. (defconstant *jmpbuf-size*
  223.   (progn
  224.     (format *query-io* #+DEUTSCH "~%Bitte *jmpbuf-size* eingeben: "
  225.                        #+ENGLISH "~%Please input *jmpbuf-size*: "
  226.     )
  227.     (read *query-io*)
  228. ) )
  229. #+CLISP1 (defconstant *big-endian* t)
  230. #+(and CROSS (not CLISP1))
  231. (defconstant *big-endian*
  232.   #+(or ATARI AMIGA SUN3 SUN4) t ; BIG-ENDIAN-Prozessor
  233.   #+(or SUN386 PC386) nil ; LITTLE-ENDIAN-Prozessor
  234.   #-(or ATARI AMIGA SUN3 SUN4 SUN386 PC386)
  235.     (y-or-n-p #+DEUTSCH "Prozessor BIG-ENDIAN?"
  236.               #+ENGLISH "processor big endian?"
  237.     )
  238. )
  239. #+CROSS
  240. (defun version ()
  241.   (list ' #+CLISP1 SYSTEM::CLISP1 #+CLISP2 SYSTEM::CLISP2 #+CLISP3 SYSTEM::CLISP3
  242.         *jmpbuf-size*
  243.         *big-endian*
  244.         '210292
  245. ) )
  246.  
  247. (defconstant *keyword-package* (find-package "KEYWORD"))
  248. (defconstant *lisp-package* (find-package "LISP"))
  249.  
  250. ; Variablen für Top-Level-Aufruf:
  251. (defvar *compiling* nil) ; gibt an, ob gerade beim Compilieren
  252. ; (defvar *error-count*) ; Anzahl der aufgetretenen Errors
  253. ; (defvar *warning-count*) ; Anzahl der aufgetretenen Warnungen
  254. (defvar *compile-warnings* t) ; ob Compiler-Warnungen ausgegeben werden
  255. (defvar *compile-verbose* t) ; ob Compiler-Kommentare ausgegeben werden
  256. (defvar *compiling-from-file*) ; NIL oder T wenn von COMPILE-FILE aufgerufen
  257. (defvar *c-listing-output*) ; Compiler-Listing-Stream oder nil
  258. (defvar *c-error-output*) ; Compiler-Error-Stream
  259. ; Es ist im wesentlichen
  260. ; *c-error-output* = (make-broadcast-stream *error-output* *c-listing-output*)
  261. (defvar *known-special-vars*) ; Namen von deklarierten dynamischen Variablen
  262. (defvar *constant-special-vars*) ; Namen und Werte von konstanten Variablen
  263.  
  264. ; Variablen für COMPILE-FILE:
  265. (defvar *fasoutput-stream* nil) ; Compiler-Output-Stream oder nil
  266. (defvar *liboutput-stream* nil) ; Compiler-Library-Stream oder nil
  267. (defvar *functions-with-errors* nil) ; Namen der Funktionen, wo es Fehler gab
  268. (defvar *known-functions*) ; Namen der bisher bekannten Funktionen,
  269.                            ; wird vom Macroexpander von DEFUN verändert
  270. (defvar *unknown-functions*) ; Namen der bisher unbekannten Funktionen
  271. (defvar *unknown-free-vars*) ; Namen von undeklarierten dynamischen Variablen
  272. (defvar *inline-functions*) ; global inline-deklarierte Funktionssymbole
  273. (defvar *notinline-functions*) ; global notinline-deklarierte Funktionssymbole
  274. (defvar *inline-definitions*) ; Aliste globaler inlinebarer Funktionsdefinitionen
  275. (defvar *user-declaration-types*) ; global definierte zusätzliche Deklarationen
  276. (defvar *compiled-modules*) ; bereits "geladene" (compilierte) Modulnamen
  277. (defvar *package-tasks*) ; noch durchzuführende Package-Anforderungen
  278.  
  279. #|
  280. Basis für den Zielcode ist eine Stackmaschine mit zwei Stacks:
  281. STACK (Stack für LISP-Objekte und Frames) und SP (Stack für sonstiges).
  282. Mehrfache Werte werden kurzfristig in A0/A1/A2/MV_SPACE (D7.W Werte, bei D7.W=0
  283. ist A0=NIL) gehalten, längerfristig auf dem STACK abgelegt.
  284.  
  285. 1. Pass des Compilers:
  286. Macro-Expansion, Codegenerierung (symbolisch), Allokation von Variablen auf
  287. dem STACK oder in Closures, Optimierung auf LISP-Ebene.
  288. Danach steht für jede beteiligte Funktion das Stack-Layout fest.
  289. Die Information steckt in einem Netz von ANODEs.
  290. 2. Pass des Compilers:
  291. Auflösung der Variablenbezüge, Optimierung auf Code-Ebene
  292. (Peephole-Optimierung), Kreation compilierter funktionaler Objekte.
  293. 3. Pass des Compilers:
  294. Auflösung von Bezügen zwischen den einzelnen funktionalen Objekten.
  295.  
  296. Zielsprache:
  297. ============
  298.  
  299. ein Bytecode-Interpreter.
  300.  
  301. Ein compiliertes funktionales Objekt (Closure) hat folgenden Aufbau:
  302. FUNC = #Closure( Name
  303.                  CODEVEC
  304.                  [VenvConst] {BlockConst}* {TagbodyConst}*
  305.                  {Keyword}* {sonstige Const}*
  306.                )
  307.  
  308. VenvConst, BlockConst, TagbodyConst : diese LISP-Objekte werden innerhalb der
  309. Funktion als Konstanten betrachtet. Sie werden beim Aufbau der Funktion zur
  310. Laufzeit mitgegeben. Sollten diese drei Teile fehlen (d.h. diese Funktion ist
  311. von der Inkarnation unabhängig, weil sie auf keine lexikalischen Variablen,
  312. Blocks oder Tags zugreift, die im compilierten Code außerhalb von ihr definiert
  313. werden), so heißt die Funktion autonom.
  314.  
  315. Keyword : die Keywords in der richtigen Reihenfolge. Werden vom Interpreter bei
  316. der Parameterübergabe gebraucht.
  317.  
  318. sonstige Const: sonstige Konstanten, auf die vom Innern der Funktion aus Bezug
  319. genommen wird. Sie sind untereinander und zu allen Keywords paarweise nicht EQL.
  320.  
  321. CODEVEC = Code-Vektor, ein SIMPLE-BIT-VECTOR,
  322.                  Falls nicht FAST_SP:
  323.                    2 Bytes : maximale SP-Tiefe
  324.                  2 Bytes : Anzahl der required parameter
  325.                  2 Bytes : Anzahl der optionalen Parameter
  326.                  1 Byte : Flags. Bit 0: ob &REST - Parameter angegeben
  327.                                  Bit 7: ob Keyword-Parameter angegeben
  328.                                  Bit 6: &ALLOW-OTHER-KEYS-Flag
  329.                                  Bit 4: ob generische Funktion
  330.                  1 Byte : Kürzel für den Argumenttyp, für schnelleres FUNCALL
  331.                  Falls Keyword-Parameter angegeben:
  332.                    4 Bytes : 2 Bytes : Anzahl der Keyword-Parameter
  333.                              2 Bytes : Offset in FUNC der Keywords
  334.                  dann
  335.                  eine Folge von Byte-Instruktionen.
  336.  
  337. |#
  338. ; externe Repräsentation einer Closure:
  339. ; #Y(name
  340. ;    #LängeY(Byte in Hex ... Byte in Hex)
  341. ;    weitere Konstanten
  342. ;   )
  343.  
  344. #-CLISP
  345. (progn
  346.   (defstruct (closure (:print-function print-closure))
  347.     name    ; der Name der Closure
  348.     codevec ; Liste der Bytes des Codevektor
  349.     consts  ; Liste der Konstanten
  350.   )
  351.   (defun print-closure (closure stream depth)
  352.     (declare (ignore depth))
  353.     (write-string "#Y(" stream)
  354.     (write (closure-name closure) :stream stream)
  355.     (write-char #\space stream)
  356.     (write-char #\# stream)
  357.     (write (length (closure-codevec closure)) :stream stream :base 10. :radix nil)
  358.     (write-char #\Y stream)
  359.     ;(write (closure-codevec closure) :stream stream :base 16.) ; stattdessen:
  360.     (write-char #\( stream)
  361.     (do ((i 0 (1- i))
  362.          (L (closure-codevec closure) (cdr L)))
  363.         ((endp L))
  364.       (when (zerop i) (write-char #\newline stream) (setq i 25))
  365.       (write-char #\space stream)
  366.       (write (car L) :stream stream :base 16. :radix nil)
  367.     )
  368.     (write-char #\) stream)
  369.     (write-char #\newline stream)
  370.     (dolist (x (closure-consts closure))
  371.       (write-char #\space stream)
  372.       (write x :stream stream)
  373.     )
  374.     (write-char #\) stream)
  375.   )
  376. )
  377.  
  378. #+CLISP
  379. (progn
  380.   (defsetf sys::%record-ref sys::%record-store)
  381.   (defsetf closure-name (closure) (new-name)
  382.     `(sys::%record-store ,closure 0 ,new-name)
  383.   )
  384.   (defun make-closure (&key name codevec consts)
  385.     (sys::%make-closure name (sys::make-code-vector codevec) consts)
  386.   )
  387. )
  388.  
  389. #-CLISP
  390. (set-dispatch-macro-character #\# #\Y
  391.   #'(lambda (stream subchar arg)
  392.       (declare (ignore subchar))
  393.       (if arg
  394.         ; Codevector lesen
  395.         (let ((obj (let ((*read-base* 16.)) (read stream t nil t))))
  396.           (unless (= (length obj) arg)
  397.             (error #+DEUTSCH "Falsche Länge eines Closure-Vektors: ~S"
  398.                    #+ENGLISH "Bad length of closure vector: ~S"
  399.                    arg
  400.           ) )
  401.           obj
  402.         )
  403.         ; Closure lesen
  404.         (let ((obj (read stream t nil t)))
  405.           (make-closure :name (first obj) :codevec (second obj) :consts (cddr obj))
  406.     ) ) )
  407. )
  408.  
  409. #|
  410. Instruktionen:
  411. Instruktionen können Operanden haben.
  412. Operanden, die Sprungziele (labels) darstellen, sind (um Codelänge zu sparen)
  413. relativ angegeben:
  414.     PC := PC(in der Instruktion) + Operand(signed)
  415. Operanden, die Zahlen darstellen, sind Integers >=0.
  416. Format der Operanden:
  417. bei LOAD, ... mit kleinem Operanden: implizit im Code.
  418. bei allen anderen Instruktionen:
  419.   nächstes Byte:
  420.     Bit 7 = 0 --> Bits 6..0 sind der Operand (7 Bits).
  421.     Bit 7 = 1 --> Bits 6..0 und nächstes Byte bilden den Operanden (15 Bits).
  422.                   Bei Sprungdistanzen: Sollte dieser =0 sein, so bilden
  423.                   die nächsten 4 Bytes den Operanden (32 Bits).
  424.  
  425.  
  426. (1) Instruktionen für Konstanten:
  427.  
  428. Mnemonic                      Bedeutung
  429.  
  430. (NIL)                         A0 := NIL, 1 Wert
  431.  
  432. (PUSH-NIL n)                  n-mal: -(STACK) := NIL, undefinierte Werte
  433.  
  434. (T)                           A0 := T, 1 Wert
  435.  
  436. (CONST n)                     A0 := Konstante Nr. n aus FUNC, 1 Wert
  437.  
  438.  
  439. (2) Instruktionen für statische Variablen
  440.  
  441. Mnemonic                      Bedeutung
  442.  
  443. (LOAD n)                      A0 := (STACK+4*n), 1 Wert
  444.  
  445. (LOADI k n)                   A0 := ((SP+4*k)+4*n), 1 Wert
  446.  
  447. (LOADC n m)                   A0 := (svref (STACK+4*n) 1+m), 1 Wert
  448.  
  449. (LOADV k m)                   A0 := (svref ... m)
  450.                                     (svref ... 0) ; k mal wiederholt
  451.                                     VenvConst,
  452.                               1 Wert
  453.  
  454. (LOADIC k n m)                A0 := (svref ((SP+4*k)+4*n) 1+m), 1 Wert
  455.  
  456. (STORE n)                     (STACK+4*n) := A0, 1 Wert
  457.  
  458. (STOREI k n)                  ((SP+4*k)+4*n) := A0, 1 Wert
  459.  
  460. (STOREC n m)                  (svref (STACK+4*n) 1+m) := A0, 1 Wert
  461.  
  462. (STOREV k m)                  (svref ... m)
  463.                               (svref ... 0) ; k mal wiederholt
  464.                               VenvConst
  465.                               := A0, 1 Wert
  466.  
  467. (STOREIC k n m)               (svref ((SP+4*k)+4*n) 1+m) := A0, 1 Wert
  468.  
  469.  
  470. (3) Instruktionen für dynamische Variablen
  471.  
  472. Mnemonic                      Bedeutung
  473.  
  474. (GETVALUE n)                  A0 := (symbol-value (CONST n)), 1 Wert
  475.  
  476. (SETVALUE n)                  (setf (symbol-value (CONST n)) A0), 1 Wert
  477.  
  478. (BIND n)                      bindet (CONST n), ein Symbol, dynamisch an A0.
  479.                               Undefinierte Werte.
  480.  
  481. (UNBIND1)                     löst einen Bindungsframe auf
  482. (UNBIND n)                    löst n Bindungsframes auf
  483.  
  484. (PROGV)                       bindet dynamisch die Symbole in der Liste
  485.                               (STACK)+ an die Werte in der Liste A0 und baut
  486.                               dabei genau einen Bindungsframe auf,
  487.                               undefinierte Werte
  488.  
  489.  
  490. (4) Instruktionen für Stackoperationen
  491.  
  492. Mnemonic                      Bedeutung
  493.  
  494. (PUSH)                        -(STACK) := A0, undefinierte Werte
  495.  
  496. (POP)                         A0 := (STACK)+, 1 Wert
  497.  
  498. (SKIP n)                      STACK := STACK+4*n
  499.  
  500. (SKIPI k n)                   STACK := (SP+4*k)+4*n, SP:=SP+4*(k+1)
  501.  
  502. (SKIPSP k)                    SP := SP+4*k
  503.  
  504.  
  505. (5) Instruktionen für Programmfluß und Sprünge
  506.  
  507. Mnemonic                      Bedeutung
  508.  
  509. (SKIP&RET n)                  STACK := STACK+4*n, beendet die Funktion
  510.                               mit den Werten A0/...
  511.  
  512. (JMP label)                   Sprung zu label
  513.  
  514. (JMPIF label)                 falls A0 /= NIL : Sprung zu label.
  515.  
  516. (JMPIFNOT label)              falls A0 = NIL : Sprung zu label.
  517.  
  518. (JMPIF1 label)                falls A0 /= NIL : 1 Wert, Sprung zu label.
  519.  
  520. (JMPIFNOT1 label)             falls A0 = NIL : 1 Wert, Sprung zu label.
  521.  
  522. (JMPIFATOM label)             falls A0 kein Cons : Sprung zu label.
  523.                               Undefinierte Werte.
  524.  
  525. (JMPIFCONSP label)            falls A0 ein Cons : Sprung zu label.
  526.                               Undefinierte Werte.
  527.  
  528. (JMPIFEQ label)               falls A0 EQ zu (STACK)+ : Sprung zu label.
  529.                               Undefinierte Werte.
  530.  
  531. (JMPIFNOTEQ label)            falls A0 nicht EQ zu (STACK)+ : Sprung zu label.
  532.                               Undefinierte Werte.
  533.  
  534. (JMPIFEQTO n label)           falls (STACK)+ EQ zu (CONST n) : Sprung zu label.
  535.                               Undefinierte Werte.
  536.  
  537. (JMPIFNOTEQTO n label)        falls (STACK)+ nicht EQ zu (CONST n) : Sprung zu label.
  538.                               Undefinierte Werte.
  539.  
  540. (JMPHASH n label)             Sucht A0 in der EQ- oder EQL-Hash-Tabelle
  541.                               (CONST n). Gefunden: Sprung ans von GETHASH
  542.                               gelieferte Label. Nicht gefunden: Sprung zu
  543.                               label. Undefinierte Werte.
  544.  
  545. (JMPHASHV n label)            Sucht A0 in der EQ- oder EQL-Hash-Tabelle
  546.                               (svref (CONST 0) n). Gefunden: Sprung ans von
  547.                               GETHASH gelieferte Label. Nicht gefunden: Sprung
  548.                               zu label. Undefinierte Werte.
  549.  
  550. (JSR label)                   Unterprogrammaufruf: lege Closure auf den STACK und
  551.                               springe zu label (mit undefinierten Werten),
  552.                               (RET) setzt das Programm an der Stelle nach
  553.                               dem (JSR label) fort.
  554.  
  555. (JMPTAIL m n label)           Wiederverwendung eines Stack-Frames: n>=m.
  556.                               Der Stack-Frame der Größe n wird auf Größe m
  557.                               verkleinert, indem die unteren m Einträge um
  558.                               n-m nach oben kopiert werden:
  559.                               (STACK+4*(n-m)...STACK+4*(n-1)) := (STACK+4*0...STACK+4*(m-1)),
  560.                               STACK := STACK + 4*(n-m),
  561.                               dann -(STACK) := Closure,
  562.                               Sprung zu label mit undefinierten Werten.
  563.  
  564.  
  565. (6) Instruktionen für Environments und Closures
  566.  
  567. Mnemonic                      Bedeutung
  568.  
  569. (VENV)                        A0 := VenvConst aus FUNC, 1 Wert
  570.  
  571. (MAKE-VECTOR1&PUSH n)         kreiert einen simple-vector mit n+1 (n>=0) Kom-
  572.                               ponenten und steckt A0 als Komponente 0 hinein.
  573.                               -(STACK) := der neue Vektor. Undefinierte Werte.
  574.  
  575. (COPY-CLOSURE m n)            kopiert die Closure (CONST m) aus FUNC und
  576.                               ersetzt in der Kopie für i=0,...,n-1 (n>0) die
  577.                               Komponente (CONST i) durch (STACK+4*(n-1-i)).
  578.                               STACK := STACK+4*n.
  579.                               A0 := Closure-Kopie, 1 Wert
  580.  
  581.  
  582. (7) Instruktionen für Funktionsaufrufe
  583.  
  584. Mnemonic                      Bedeutung
  585.  
  586. (CALL k n)                    ruft die Funktion (CONST n) mit k Argumenten
  587.                               (STACK+4*(k-1)),...,(STACK+4*0) auf,
  588.                               STACK:=STACK+4*k,
  589.                               Ergebnis kommt nach A0/...
  590.  
  591. (CALL0 n)                     ruft die Funktion (CONST n) mit 0 Argumenten
  592.                               auf, Ergebnis kommt nach A0/...
  593.  
  594. (CALL1 n)                     ruft die Funktion (CONST n) mit einem Argument
  595.                               (STACK)+ auf, Ergebnis kommt nach A0/...
  596.  
  597. (CALL2 n)                     ruft die Funktion (CONST n) mit zwei Argumenten
  598.                               4(STACK),(STACK) auf, STACK:=STACK+8,
  599.                               Ergebnis kommt nach A0/...
  600.  
  601. (CALLS1 n)                    ruft die Funktion (FUNTAB n)
  602. (CALLS2 n)                    bzw. (FUNTAB 256+n)
  603.                               (ein SUBR ohne Rest-Parameter) auf,
  604.                               mit der korrekten Argumentezahl auf dem STACK.
  605.                               STACK wird bereinigt, Ergebnis kommt nach A0/...
  606.  
  607. (CALLSR m n)                  ruft die Funktion (FUNTABR n)
  608.                               (ein SUBR mit Rest-Parameter) auf,
  609.                               mit der korrekten Argumentezahl und zusätzlich
  610.                               m restlichen Argumenten auf dem STACK.
  611.                               STACK wird bereinigt, Ergebnis kommt nach A0/...
  612.  
  613. (CALLC)                       ruft die Funktion A0 (eine compilierte Closure
  614.                               ohne Keyword-Parameter) auf. Argumente
  615.                               sind schon im richtigen Format auf dem STACK,
  616.                               STACK wird bereinigt, Ergebnis kommt nach A0/...
  617.  
  618. (CALLCKEY)                    ruft die Funktion A0 (eine compilierte Closure
  619.                               mit Keyword-Parameter) auf. Argumente
  620.                               sind schon im richtigen Format auf dem STACK,
  621.                               STACK wird bereinigt, Ergebnis kommt nach A0/...
  622.  
  623. (FUNCALL n)                   ruft die Funktion (STACK+4*n) mit n (n>=0)
  624.                               Argumenten (alle auf dem Stack) auf,
  625.                               STACK:=STACK+4*(n+1)
  626.                               Ergebnis kommt nach A0/...
  627.  
  628. (APPLY n)                     ruft die Funktion (STACK+4*n) mit n (n>=0)
  629.                               Argumenten (alle auf dem Stack) und weiteren
  630.                               Argumenten (Liste in A0) auf,
  631.                               STACK:=STACK+4*(n+1),
  632.                               Ergebnis kommt nach A0/...
  633.  
  634.  
  635. (8) Instruktionen für optionale und Keyword-Argumente
  636.  
  637. Mnemonic                      Bedeutung
  638.  
  639. (PUSH-UNBOUND n)              n-mal: -(STACK) := #<UNBOUND>, undefinierte Werte
  640.  
  641. (UNLIST n m)                  Liste A0 n mal verkürzen: -(STACK) := (car A0),
  642.                               A0 := (cdr A0). Bei den letzten m Mal darf A0
  643.                               schon zu Ende sein, dann -(STACK) := #<UNBOUND>
  644.                               stattdessen. Am Schluß muß A0 = NIL sein,
  645.                               undefinierte Werte. 0 <= m <= n.
  646.  
  647. (UNLIST* n m)                 Liste A0 n mal verkürzen: -(STACK) := (car A0),
  648.                               A0 := (cdr A0). Bei den letzten m Mal darf A0
  649.                               schon zu Ende sein, dann -(STACK) := #<UNBOUND>.
  650.                               stattdessen. Dann -(STACK) := (nthcdr n A0),
  651.                               undefinierte Werte. 0 <= m <= n, n > 0.
  652.  
  653. (JMPIFBOUNDP n label)         falls (STACK+4*n) /= #<UNBOUND> :
  654.                                 Sprung zu label, A0 := (STACK+4*n), 1 Wert.
  655.                               Sonst undefinierte Werte.
  656.  
  657. (BOUNDP n)                    A0 := (NIL falls (STACK+4*n)=#<UNBOUND>, T sonst), 1 Wert
  658.  
  659. (UNBOUND->NIL n)              Falls (STACK+4*n) = #<UNBOUND>: (STACK+4*n) := NIL
  660.  
  661.  
  662. (9) Instruktionen zur Behandlung mehrerer Werte
  663.  
  664. Mnemonic                      Bedeutung
  665.  
  666. (VALUES0)                     A0 := NIL, 0 Werte
  667.  
  668. (VALUES1)                     A0 := A0, 1 Wert
  669.  
  670. (STACK-TO-MV n)               holt n Werte von (STACK)+ herab,
  671.                               STACK:=STACK+4*n
  672.  
  673. (MV-TO-STACK)                 Multiple Values A0/A1/... auf -(STACK), 1. Wert
  674.                               zuoberst, STACK:=STACK-4*D7.W,
  675.                               danach undefinierte Werte
  676.  
  677. (NV-TO-STACK n)               die ersten n Werte (n>=0) auf -(STACK), 1. Wert
  678.                               zuoberst, STACK:=STACK-4*n, undefinierte Werte
  679.  
  680. (MV-TO-LIST)                  Multiple Values A0/... als Liste nach A0, 1 Wert
  681.  
  682. (LIST-TO-MV)                  A0/... := (values-list A0)
  683.  
  684. (MVCALLP)                     rette STACK auf -(SP), rette A0 auf -(STACK)
  685.  
  686. (MVCALL)                      führe einen Funktionsaufruf aus, wobei zwischen
  687.                               STACK und STACK:=(SP)+ die Funktion (ganz oben)
  688.                               und die Argumente stehen,
  689.                               Ergebnis kommt nach A0/...
  690.  
  691.  
  692. (10) Instruktionen für BLOCK
  693.  
  694. Mnemonic                      Bedeutung
  695.  
  696. (BLOCK-OPEN n label)          Legt einen Block-Cons (mit CAR=(CONST n) und
  697.                               CDR=Framepointer) auf -(STACK) ab, baut einen
  698.                               Block-Frame auf. Bei einem RETURN auf diesen
  699.                               Frame wird zu label gesprungen.
  700.  
  701. (BLOCK-CLOSE)                 Verlasse den Block und baue dabei einen Block-
  702.                               Frame ab (inklusive der Block-Cons-Variablen)
  703.  
  704. (RETURN-FROM n)               Verlasse den Block, dessen Block-Cons
  705.                               (CONST n) ist, mit den Werten A0/...
  706.  
  707.  
  708. (11) Instruktionen für TAGBODY
  709.  
  710. Mnemonic                      Bedeutung
  711.  
  712. (TAGBODY-OPEN m label1 ... labelm)
  713.                               Legt einen Tagbody-Cons (mit CAR = m als Fixnum
  714.                               und CDR=Framepointer) auf -(STACK) ab, baut
  715.                               einen Tagbody-Frame auf. Bei einem GO mit
  716.                               Nummer k wird zu labelk gesprungen.
  717.                               Undefinierte Werte.
  718.  
  719. (TAGBODY-CLOSE-NIL)           Verlasse den Tagbody und baue dabei einen
  720.                               Tagbody-Frame ab (inklusive der Tagbody-Cons-
  721.                               Variablen).
  722.                               A0 := NIL, 1 Wert
  723.  
  724. (TAGBODY-CLOSE)               Verlasse den Tagbody und baue dabei
  725.                               einen Tagbody-Frame ab (inklusive der
  726.                               Tagbody-Cons-Variablen).
  727.  
  728. (GO n k)                      Springe im Tagbody, dessen Tagbody-Cons
  729.                               (CONST n) ist, an Tag Nummer k
  730.  
  731.  
  732. (12) Instruktionen für CATCH und THROW
  733.  
  734. Mnemonic                      Bedeutung
  735.  
  736. (CATCH-OPEN label)            baut einen CATCH-Frame auf mit A0 als Tag;
  737.                               bei einem THROW auf dieses Tag wird zu label
  738.                               gesprungen
  739.  
  740. (CATCH-CLOSE)                 löst einen CATCH-Frame auf
  741.  
  742. (THROW)                       führt ein THROW auf den Catch-Tag (STACK)+ aus,
  743.                               mit den Werten A0/...
  744.  
  745.  
  746. (13) Instruktionen für UNWIND-PROTECT
  747.  
  748. Mnemonic                      Bedeutung
  749.  
  750. (UNWIND-PROTECT-OPEN label)   baut einen UNWIND-PROTECT-Frame auf;
  751.                               bei einem Unwind wird unter Rettung
  752.                               der Werte zu label gesprungen
  753.  
  754. (UNWIND-PROTECT-NORMAL-EXIT)  löst einen Unwind-Protect-Frame auf, schreibt
  755.                               eine Weitermach-Adresse auf SP, rettet die
  756.                               Werte und fängt an, den folgenden Cleanup-Code
  757.                               auszuführen
  758.  
  759. (UNWIND-PROTECT-CLOSE)        beendet den Cleanup-Code: schreibt die
  760.                               geretteten Werte zurück, führt ein RTS aus
  761.  
  762. (UNWIND-PROTECT-CLEANUP)      löst einen Unwind-Protect-Frame auf,
  763.                               schreibt eine Weitermach-Adresse und
  764.                               den PC auf SP, rettet die Werte und
  765.                               fängt an, den Cleanup-Code auszuführen
  766.  
  767.  
  768. (14) Kurz-Instruktionen für einige Funktionen
  769.  
  770. Mnemonic                      Bedeutung
  771.  
  772. (NOT)                         A0 := (not A0), 1 Wert
  773.  
  774. (EQ)                          A0 := (eq (STACK)+ A0), 1 Wert
  775.  
  776. (CAR)                         A0 := (car A0), 1 Wert
  777.  
  778. (CDR)                         A0 := (cdr A0), 1 Wert
  779.  
  780. (CONS)                        A0 := (cons (STACK)+ A0), 1 Wert
  781.  
  782. (SYMBOL-FUNCTION)             A0 := (symbol-function A0), 1 Wert
  783.  
  784. (SVREF)                       A0 := (svref (STACK)+ A0), 1 Wert
  785.  
  786. (SVSET)                       (setf (svref (STACK) A0) (STACK+4)),
  787.                               A0 := (STACK+4), 1 Wert, STACK:=STACK+8
  788.  
  789. (LIST n)                      Bildet eine Liste aus den untersten n auf dem STACK
  790.                               liegenden Objekten, STACK := STACK + 4*n,
  791.                               Liste nach A0, 1 Wert
  792.  
  793. (LIST* n)                     Bildet eine Liste aus den untersten n auf dem STACK
  794.                               liegenden Objekten und A0, STACK := STACK + 4*n,
  795.                               Liste nach A0, 1 Wert
  796.  
  797. (ERROR n)                     ruft ERROR mit n+1 Argumenten (auf dem STACK) auf
  798.  
  799.  
  800. (15)
  801. Zusätzlich gibt es kombinierte Operationen im Format
  802. (<OP1>&<OP2>&...&<OPn> <Operanden_1> <Operanden_2> ... <Operanden_n>) .
  803.  
  804. Mnemonic                           Bedeutung
  805.  
  806. (NIL&PUSH)                         (NIL) (PUSH)
  807. (T&PUSH)                           (T) (PUSH)
  808. (CONST&PUSH n)                     (CONST n) (PUSH)
  809. (LOAD&PUSH n)                      (LOAD n) (PUSH)
  810. (LOADI&PUSH k n)                   (LOADI k n) (PUSH)
  811. (LOADC&PUSH n m)                   (LOADC n m) (PUSH)
  812. (LOADV&PUSH k m)                   (LOADV k m) (PUSH)
  813. (POP&STORE n)                      (POP) (STORE n)
  814. (GETVALUE&PUSH n)                  (GETVALUE n) (PUSH)
  815. (JSR&PUSH label)                   (JSR label) (PUSH)
  816. (COPY-CLOSURE&PUSH m n)            (COPY-CLOSURE m n) (PUSH)
  817. (CALL&PUSH k n)                    (CALL k n) (PUSH)
  818. (CALL1&PUSH n)                     (CALL1 n) (PUSH)
  819. (CALL2&PUSH n)                     (CALL2 n) (PUSH)
  820. (CALLS1&PUSH n)                    (CALLS1 n) (PUSH)
  821. (CALLS2&PUSH n)                    (CALLS2 n) (PUSH)
  822. (CALLSR&PUSH m n)                  (CALLSR m n) (PUSH)
  823. (CALLC&PUSH)                       (CALLC) (PUSH)
  824. (CALLCKEY&PUSH)                    (CALLCKEY) (PUSH)
  825. (FUNCALL&PUSH n)                   (FUNCALL n) (PUSH)
  826. (APPLY&PUSH n)                     (APPLY n) (PUSH)
  827. (CAR&PUSH)                         (CAR) (PUSH)
  828. (CDR&PUSH)                         (CDR) (PUSH)
  829. (CONS&PUSH)                        (CONS) (PUSH)
  830. (LIST&PUSH n)                      (LIST n) (PUSH)
  831. (LIST*&PUSH n)                     (LIST* n) (PUSH)
  832. (NIL&STORE n)                      (NIL) (STORE n)
  833. (T&STORE n)                        (T) (STORE n)
  834. (LOAD&STOREC k n m)                (LOAD k) (STOREC n m)
  835. (CALLS1&STORE n k)                 (CALLS1 n) (STORE k)
  836. (CALLS2&STORE n k)                 (CALLS2 n) (STORE k)
  837. (CALLSR&STORE m n k)               (CALLSR m n) (STORE k)
  838. (LOAD&CDR&STORE n)                 (LOAD n) (CDR) (STORE n)
  839. (LOAD&CONS&STORE n)                (LOAD n+1) (CONS) (STORE n)
  840. (LOAD&INC&STORE n)                 (LOAD n) (CALL1 #'1+) (STORE n)
  841. (LOAD&DEC&STORE n)                 (LOAD n) (CALL1 #'1-) (STORE n)
  842. (LOAD&CAR&STORE m n)               (LOAD m) (CAR) (STORE n)
  843. (CALL1&JMPIF n label)              (CALL1 n) (JMPIF label)
  844. (CALL1&JMPIFNOT n label)           (CALL1 n) (JMPIFNOT label)
  845. (CALL2&JMPIF n label)              (CALL2 n) (JMPIF label)
  846. (CALL2&JMPIFNOT n label)           (CALL2 n) (JMPIFNOT label)
  847. (CALLS1&JMPIF n label)             (CALLS1 n) (JMPIF label)
  848. (CALLS1&JMPIFNOT n label)          (CALLS1 n) (JMPIFNOT label)
  849. (CALLS2&JMPIF n label)             (CALLS2 n) (JMPIF label)
  850. (CALLS2&JMPIFNOT n label)          (CALLS2 n) (JMPIFNOT label)
  851. (CALLSR&JMPIF m n label)           (CALLSR m n) (JMPIF label)
  852. (CALLSR&JMPIFNOT m n label)        (CALLSR m n) (JMPIFNOT label)
  853. (LOAD&JMPIF n label)               (LOAD n) (JMPIF label)
  854. (LOAD&JMPIFNOT n label)            (LOAD n) (JMPIFNOT label)
  855. (LOAD&CAR&PUSH n)                  (LOAD n) (CAR) (PUSH)
  856. (LOAD&CDR&PUSH n)                  (LOAD n) (CDR) (PUSH)
  857. (LOAD&INC&PUSH n)                  (LOAD n) (CALL1 #'1+) (PUSH)
  858. (LOAD&DEC&PUSH n)                  (LOAD n) (CALL1 #'1-) (PUSH)
  859. (CONST&SYMBOL-FUNCTION n)          (CONST n) (SYMBOL-FUNCTION)
  860. (CONST&SYMBOL-FUNCTION&PUSH n)     (CONST n) (SYMBOL-FUNCTION) (PUSH)
  861. (CONST&SYMBOL-FUNCTION&STORE n k)  (CONST n) (SYMBOL-FUNCTION) (STORE k)
  862.  
  863.  
  864. |#
  865.  
  866. ; Instruktionen-Klassifikation:
  867. ; O = Instruktion ohne Operand
  868. ; K = numerischer Operand oder
  869. ;     Kurz-Operand (dann ist das Byte = short-code-ops[x] + Operand)
  870. ; N = numerischer Operand
  871. ; B = Byte-Operand
  872. ; L = Label-Operand
  873. ; NH = numerischer Operand, der eine Hashtable referenziert
  874. ; LX = so viele Label-Operanden, wie der vorangehende Operand angibt
  875.  
  876. ; Die Position in der Instruction-Table liefert den eigentlichen Code der
  877. ; Instruktion (>= 0, < short-code-base), Codes >= short-code-base werden
  878. ; von den K-Instruktionen belegt.
  879. (defconstant instruction-table
  880.   '#(; (1) Konstanten
  881.      (NIL O) (PUSH-NIL N) (T O) (CONST K)
  882.      ; (2) statische Variablen
  883.      (LOAD K) (LOADI NN) (LOADC NN) (LOADV NN) (LOADIC NNN)
  884.      (STORE K) (STOREI NN) (STOREC NN) (STOREV NN) (STOREIC NNN)
  885.      ; (3) dynamische Variablen
  886.      (GETVALUE N) (SETVALUE N) (BIND N) (UNBIND1 O) (UNBIND N) (PROGV O)
  887.      ; (4) Stackoperationen
  888.      (PUSH O) (POP O) (SKIP N) (SKIPI NN) (SKIPSP N)
  889.      ; (5) Programmfluß und Sprünge
  890.      (SKIP&RET N) (JMP L) (JMPIF L) (JMPIFNOT L) (JMPIF1 L) (JMPIFNOT1 L)
  891.      (JMPIFATOM L) (JMPIFCONSP L) (JMPIFEQ L) (JMPIFNOTEQ L)
  892.      (JMPIFEQTO NL) (JMPIFNOTEQTO NL) (JMPHASH NHL) (JMPHASHV NHL) (JSR L)
  893.      (JMPTAIL NNL)
  894.      ; (6) Environments und Closures
  895.      (VENV O) (MAKE-VECTOR1&PUSH N) (COPY-CLOSURE NN)
  896.      ; (7) Funktionsaufrufe
  897.      (CALL NN) (CALL0 N) (CALL1 N) (CALL2 N)
  898.      (CALLS1 B) (CALLS2 B) (CALLSR NB) (CALLC O) (CALLCKEY O)
  899.      (FUNCALL N) (APPLY N)
  900.      ; (8) optionale und Keyword-Argumente
  901.      (PUSH-UNBOUND N) (UNLIST NN) (UNLIST* NN) (JMPIFBOUNDP NL) (BOUNDP N)
  902.      (UNBOUND->NIL N)
  903.      ; (9) Behandlung mehrerer Werte
  904.      (VALUES0 O) (VALUES1 O) (STACK-TO-MV N) (MV-TO-STACK O) (NV-TO-STACK N)
  905.      (MV-TO-LIST O) (LIST-TO-MV O) (MVCALLP O) (MVCALL O)
  906.      ; (10) BLOCK
  907.      (BLOCK-OPEN NL) (BLOCK-CLOSE O) (RETURN-FROM N)
  908.      ; (11) TAGBODY
  909.      (TAGBODY-OPEN NLX) (TAGBODY-CLOSE-NIL O) (TAGBODY-CLOSE O) (GO NN)
  910.      ; (12) CATCH und THROW
  911.      (CATCH-OPEN L) (CATCH-CLOSE O) (THROW O)
  912.      ; (13) UNWIND-PROTECT
  913.      (UNWIND-PROTECT-OPEN L) (UNWIND-PROTECT-NORMAL-EXIT O)
  914.      (UNWIND-PROTECT-CLOSE O) (UNWIND-PROTECT-CLEANUP O)
  915.      ; (14) einige Funktionen
  916.      (NOT O) (EQ O) (CAR O) (CDR O) (CONS O) (SYMBOL-FUNCTION O) (SVREF O)
  917.      (SVSET O) (LIST N) (LIST* N) (ERROR N)
  918.      ; (15) kombinierte Operationen
  919.      (NIL&PUSH O) (T&PUSH O) (CONST&PUSH K)
  920.      (LOAD&PUSH K) (LOADI&PUSH NN) (LOADC&PUSH NN) (LOADV&PUSH NN) (POP&STORE N)
  921.      (GETVALUE&PUSH N)
  922.      (JSR&PUSH L)
  923.      (COPY-CLOSURE&PUSH NN)
  924.      (CALL&PUSH NN) (CALL1&PUSH N) (CALL2&PUSH N)
  925.      (CALLS1&PUSH B) (CALLS2&PUSH B) (CALLSR&PUSH NB)
  926.      (CALLC&PUSH O) (CALLCKEY&PUSH O)
  927.      (FUNCALL&PUSH N) (APPLY&PUSH N)
  928.      (CAR&PUSH O) (CDR&PUSH O) (CONS&PUSH O)
  929.      (LIST&PUSH N) (LIST*&PUSH N)
  930.      (NIL&STORE N) (T&STORE N) (LOAD&STOREC NNN)
  931.      (CALLS1&STORE BN) (CALLS2&STORE BN) (CALLSR&STORE NBN)
  932.      (LOAD&CDR&STORE N) (LOAD&CONS&STORE N) (LOAD&INC&STORE N) (LOAD&DEC&STORE N)
  933.      (LOAD&CAR&STORE NN)
  934.      (CALL1&JMPIF NL) (CALL1&JMPIFNOT NL)
  935.      (CALL2&JMPIF NL) (CALL2&JMPIFNOT NL)
  936.      (CALLS1&JMPIF BL) (CALLS1&JMPIFNOT BL)
  937.      (CALLS2&JMPIF BL) (CALLS2&JMPIFNOT BL)
  938.      (CALLSR&JMPIF NBL) (CALLSR&JMPIFNOT NBL)
  939.      (LOAD&JMPIF NL) (LOAD&JMPIFNOT NL)
  940.      (LOAD&CAR&PUSH N) (LOAD&CDR&PUSH N) (LOAD&INC&PUSH N) (LOAD&DEC&PUSH N)
  941.      (CONST&SYMBOL-FUNCTION N) (CONST&SYMBOL-FUNCTION&PUSH N)
  942.      (CONST&SYMBOL-FUNCTION&STORE NN)
  943.      (APPLY&SKIP&RET NN)
  944. )   )
  945. (dotimes (i (length instruction-table))
  946.   (setf (get (first (svref instruction-table i)) 'INSTRUCTION) i)
  947. )
  948. (defconstant instruction-codes
  949.   (let ((hashtable (make-hash-table :test #'eq)))
  950.     (dotimes (i (length instruction-table))
  951.       (setf (gethash (first (svref instruction-table i)) hashtable) i)
  952.     )
  953.     hashtable
  954. ) )
  955.  
  956. ; K-Instruktionen:
  957. (defconstant instruction-table-K
  958.  '#(LOAD LOAD&PUSH CONST CONST&PUSH STORE)
  959. )
  960. (defconstant short-code-base 152)
  961. (defconstant short-code-opsize '#(15   25   21   33   10))
  962. (defconstant short-code-ops '#(152  167  192  213  246));256
  963.  
  964.  
  965. #|
  966.  
  967. Zwischensprache nach dem 1. Pass:
  968. =================================
  969.  
  970. 1. Konstanten:
  971.  
  972. (NIL)                            A0 := NIL, 1 Wert
  973.  
  974. (PUSH-NIL n)                     n-mal: -(STACK) := NIL, undefinierte Werte
  975.  
  976. (T)                              A0 := T, 1 Wert
  977.  
  978. (CONST const)                    A0 := 'const, 1 Wert
  979.  
  980. (FCONST fnode)                   A0 := das Compilat des fnode, 1 Wert
  981.  
  982. (BCONST block)                   A0 := das Block-Cons dieses Blockes (eine
  983.                                  Konstante aus FUNC), 1 Wert
  984.  
  985. (GCONST tagbody)                 A0 := das Tagbody-Cons dieses Tagbody (eine
  986.                                  Konstante aus FUNC), 1 Wert
  987.  
  988. 2.,3. Variablen:
  989.  
  990. (GET var venvc stackz)           A0 := var, 1 Wert
  991.                                  (venvc ist das aktuelle Closure-Venv,
  992.                                   stackz der aktuelle Stackzustand)
  993.  
  994. (SET var venvc stackz)           var := A0, 1 Wert
  995.                                  (venvc ist das aktuelle Closure-Venv,
  996.                                   stackz der aktuelle Stackzustand)
  997.  
  998. (STORE n)                        (STACK+4*n) := A0, 1 Wert
  999.  
  1000. (GETVALUE symbol)                A0 := (symbol-value 'symbol), 1 Wert
  1001.  
  1002. (SETVALUE symbol)                (setf (symbol-value 'symbol) A0), 1 Wert
  1003.  
  1004. (BIND const)                     bindet const (ein Symbol) dynamisch an A0.
  1005.                                  Undefinierte Werte.
  1006.  
  1007. (UNBIND1)                        löst einen Bindungsframe auf
  1008.  
  1009. (PROGV)                          bindet dynamisch die Symbole in der Liste
  1010.                                  (STACK)+ an die Werte in der Liste A0 und
  1011.                                  baut dabei genau einen Bindungsframe auf,
  1012.                                  undefinierte Werte
  1013.  
  1014. 4. Stackoperationen:
  1015.  
  1016. (PUSH)                           -(STACK) := A0, undefinierte Werte
  1017.  
  1018. (POP)                            A0 := (STACK)+, 1 Wert
  1019.  
  1020. (UNWIND stackz1 stackz2 for-value) Führt ein Unwind binnen einer Funktion aus:
  1021.                                  Bereinigt den Stack, um vom Stackzustand
  1022.                                  stackz1 zum Stackzustand stackz2 zu kommen.
  1023.                                  Löst dazwischen liegende Frames auf. for-value
  1024.                                  gibt an, ob dabei die Werte A0/... gerettet
  1025.                                  werden müssen.
  1026.  
  1027. 5. Programmfluß und Sprünge:
  1028.  
  1029. (RET)                            beendet die Funktion mit den Werten A0/...
  1030.  
  1031. (JMP label)                      Sprung zu label
  1032.  
  1033. (JMPIF label)                    falls A0 /= NIL : Sprung zu label.
  1034.  
  1035. (JMPIFNOT label)                 falls A0 = NIL : Sprung zu label.
  1036.  
  1037. (JMPIF1 label)                   falls A0 /= NIL : 1 Wert, Sprung zu label.
  1038.  
  1039. (JMPIFNOT1 label)                falls A0 = NIL : 1 Wert, Sprung zu label.
  1040.  
  1041. (JMPHASH test ((obj1 . label1) ... (objm . labelm)) label . labels)
  1042.                                  Sprung zu labeli, falls A0 = obji (im Sinne
  1043.                                  des angegebenen Vergleichs), sonst zu label.
  1044.                                  Undefinierte Werte.
  1045.  
  1046. (JSR m label)                    ruft den Code ab label als Unterprogramm auf,
  1047.                                  mit m Argumenten auf dem Stack
  1048.  
  1049. 6. Environments und Closures:
  1050.  
  1051. (VENV venvc stackz)              A0 := das Venv, das venvc entspricht
  1052.                                  (aus dem Stack, als Konstante aus
  1053.                                  FUNC, oder NIL, falls in FUNC nicht vorhanden),
  1054.                                  1 Wert
  1055.                                  (stackz ist der aktuelle Stackzustand)
  1056.  
  1057. (MAKE-VECTOR1&PUSH n)            kreiert einen simple-vector mit n+1 (n>=0)
  1058.                                  Komponenten und steckt A0 als Komponente 0
  1059.                                  hinein. -(STACK) := der neue Vektor.
  1060.                                  Undefinierte Werte.
  1061.  
  1062. (COPY-CLOSURE fnode n)           kopiert die Closure, die dem fnode entspricht
  1063.                                  und ersetzt in der Kopie für i=0,...,n-1 (n>0)
  1064.                                  die Komponente (CONST i) durch (STACK+4*(n-1-i)).
  1065.                                  STACK := STACK+4*n. A0 := Closure-Kopie, 1 Wert
  1066.  
  1067. 7. Funktionsaufrufe:
  1068.  
  1069. (CALLP)                          beginnt den Aufbau eines Funktionsaufruf-Frames
  1070.                                  (wird im 2. Pass ersatzlos gestrichen)
  1071.  
  1072. (CALL k const)                   ruft die Funktion const mit k Argumenten
  1073.                                  (STACK+4*(k-1)),...,(STACK+4*0) auf,
  1074.                                  STACK:=STACK+4*k, Ergebnis kommt nach A0/...
  1075.  
  1076. (CALL0 const)                    ruft die Funktion const mit 0 Argumenten auf,
  1077.                                  Ergebnis kommt nach A0/...
  1078.  
  1079. (CALL1 const)                    ruft die Funktion const mit 1 Argument A0 auf,
  1080.                                  Ergebnis kommt nach A0/...
  1081.  
  1082. (CALL2 const)                    ruft die Funktion const mit 2 Argumenten (STACK)
  1083.                                  und A0 auf, STACK:=STACK+4,
  1084.                                  Ergebnis kommt nach A0/...
  1085.  
  1086. (CALLS1 n)                       ruft die Funktion (FUNTAB n)
  1087. (CALLS2 n)                       bzw. (FUNTAB 256+n)
  1088.                                  (ein SUBR ohne Rest-Parameter) auf,
  1089.                                  mit der korrekten Argumentezahl auf dem STACK.
  1090.                                  STACK wird bereinigt, Ergebnis kommt nach A0/...
  1091.  
  1092. (CALLSR m n)                     ruft die Funktion (FUNTABR n)
  1093.                                  (ein SUBR mit Rest-Parameter) auf,
  1094.                                  mit der korrekten Argumentezahl und zusätzlich
  1095.                                  m restlichen Argumenten auf dem STACK.
  1096.                                  STACK wird bereinigt, Ergebnis kommt nach A0/...
  1097.  
  1098. (CALLC)                          ruft die Funktion A0 (eine compilierte Closure
  1099.                                  ohne Keyword-Parameter) auf. Argumente
  1100.                                  sind schon im richtigen Format auf dem STACK,
  1101.                                  STACK wird bereinigt, Ergebnis kommt nach A0/...
  1102.  
  1103. (CALLCKEY)                       ruft die Funktion A0 (eine compilierte Closure
  1104.                                  mit Keyword-Parameter) auf. Argumente
  1105.                                  sind schon im richtigen Format auf dem STACK,
  1106.                                  STACK wird bereinigt, Ergebnis kommt nach A0/...
  1107.  
  1108. (FUNCALLP)                       fängt den Aufbau eines FUNCALL-Frames an,
  1109.                                  auszuführende Funktion ist in A0
  1110.  
  1111. (FUNCALL n)                      ruft die angegebene Funktion mit n (n>=0)
  1112.                                  Argumenten (alle auf dem Stack) auf,
  1113.                                  beseitigt den FUNCALL-Frame,
  1114.                                  Ergebnis kommt nach A0/...
  1115.  
  1116. (APPLYP)                         fängt den Aufbau eines APPLY-Frames an,
  1117.                                  auszuführende Funktion ist in A0
  1118.  
  1119. (APPLY n)                        ruft die angegebene Funktion mit n (n>=0)
  1120.                                  Argumenten (alle auf dem Stack) und weiteren
  1121.                                  Argumenten (Liste in A0) auf,
  1122.                                  beseitigt den APPLY-Frame,
  1123.                                  Ergebnis kommt nach A0/...
  1124.  
  1125. 8. optionale und Keyword-Argumente:
  1126.  
  1127. (PUSH-UNBOUND n)                 n-mal: -(STACK) := #<UNBOUND>, undefinierte Werte
  1128.  
  1129. (UNLIST n m)                     Liste A0 n mal verkürzen: -(STACK) := (car A0),
  1130.                                  A0 := (cdr A0). Bei den letzten m Mal darf A0
  1131.                                  schon zu Ende sein, dann -(STACK) := #<UNBOUND>
  1132.                                  stattdessen. Am Schluß muß A0 = NIL sein,
  1133.                                  undefinierte Werte. 0 <= m <= n.
  1134.  
  1135. (UNLIST* n m)                    Liste A0 n mal verkürzen: -(STACK) := (car A0),
  1136.                                  A0 := (cdr A0). Bei den letzten m Mal darf A0
  1137.                                  schon zu Ende sein, dann -(STACK) := #<UNBOUND>.
  1138.                                  stattdessen. Dann -(STACK) := (nthcdr n A0),
  1139.                                  undefinierte Werte. 0 <= m <= n, n > 0.
  1140.  
  1141. (JMPIFBOUNDP var venvc stackz label)
  1142.                                  falls Variable /= #<UNBOUND> :
  1143.                                    Sprung zu label, A0 := Variable, 1 Wert.
  1144.                                  Sonst undefinierte Werte.
  1145.                                  (stackz ist der aktuelle Stackzustand)
  1146.  
  1147. (BOUNDP var venvc stackz)        A0 := (NIL falls Variable=#<UNBOUND>, T sonst),
  1148.                                  1 Wert
  1149.                                  (stackz ist der aktuelle Stackzustand)
  1150.  
  1151. 9. Behandlung mehrerer Werte:
  1152.  
  1153. (VALUES0)                        A0 := NIL, 0 Werte
  1154.  
  1155. (VALUES1)                        A0 := A0, 1 Wert
  1156.  
  1157. (STACK-TO-MV n)                  holt n Werte von (STACK)+ herab,
  1158.                                  STACK:=STACK+4*n, n>1
  1159.  
  1160. (MV-TO-STACK)                    Multiple Values A0/A1/... auf -(STACK),
  1161.                                  1. Wert zuoberst, STACK:=STACK-4*D7.W,
  1162.                                  danach undefinierte Werte
  1163.  
  1164. (NV-TO-STACK n)                  die ersten n Werte (n>=0) auf -(STACK),
  1165.                                  1. Wert zuoberst, STACK:=STACK-4*n,
  1166.                                  undefinierte Werte
  1167.  
  1168. (MV-TO-LIST)                     Multiple Values A0/... als Liste nach A0,
  1169.                                  1 Wert
  1170.  
  1171. (LIST-TO-MV)                     A0/... := (values-list A0)
  1172.  
  1173. (MVCALLP)                        bereitet einen MULTIPLE-VALUE-CALL auf die
  1174.                                  Funktion in A0 vor
  1175.  
  1176. (MVCALL)                         führt einen MULTIPLE-VALUE-CALL mit den im
  1177.                                  Stack liegenden Argumenten aus
  1178.  
  1179. 10. BLOCK:
  1180.  
  1181. (BLOCK-OPEN const label)         Legt einen Block-Cons (mit CAR=const und CDR=
  1182.                                  Framepointer) auf -(STACK) ab, baut einen
  1183.                                  Block-Frame auf. Bei einem RETURN auf diesen
  1184.                                  Frame wird zu label gesprungen.
  1185.  
  1186. (BLOCK-CLOSE)                    Verlasse den Block und baue dabei einen Block-
  1187.                                  Frame ab (inklusive der Block-Cons-Variablen)
  1188.  
  1189. (RETURN-FROM const)              Verlasse den Block, dessen Block-Cons angegeben
  1190.                                  ist, mit den Werten A0/...
  1191. (RETURN-FROM block)              Verlasse den angegebenen Block (sein Block-Cons
  1192.                                  kommt unter den BlockConsts von FUNC vor) mit
  1193.                                  den Werten A0/...
  1194.  
  1195. 11. TAGBODY:
  1196.  
  1197. (TAGBODY-OPEN m label1 ... labelm)
  1198.                                  Legt einen Tagbody-Cons (mit CAR=m als Fixnum
  1199.                                  und CDR=Framepointer) auf -(STACK) ab, baut einen
  1200.                                  Tagbody-Frame auf. Bei einem GO mit Nummer k
  1201.                                  wird zu labelk gesprungen.
  1202.  
  1203. (TAGBODY-CLOSE-NIL)              Verlasse den Tagbody und baue dabei einen
  1204.                                  Tagbody-Frame ab (inklusive der Tagbody-Cons-
  1205.                                  Variablen). A0 := NIL, 1 Wert
  1206.  
  1207. (TAGBODY-CLOSE)                  Verlasse den Tagbody und baue dabei einen
  1208.                                  Tagbody-Frame ab (inklusive der Tagbody-Cons-
  1209.                                  Variablen).
  1210.  
  1211. (GO const k)                     Springe im Tagbody, dessen Tagbody-Cons
  1212.                                  angegeben ist, an Tag (svref (car const) k)
  1213. (GO tagbody k)                   Springe im angegebenen Tagbody an Tag Nummer k
  1214.                                  in (tagbody-used-far tagbody)
  1215.  
  1216. 12. CATCH und THROW:
  1217.  
  1218. (CATCH-OPEN label)               baut einen CATCH-Frame auf mit A0 als Tag;
  1219.                                  bei einem THROW auf dieses Tag wird zu label
  1220.                                  gesprungen
  1221.  
  1222. (CATCH-CLOSE)                    löst einen CATCH-Frame auf
  1223.  
  1224. (THROW)                          führt ein THROW auf den Catch-Tag (STACK)+
  1225.                                  aus, mit den Werten A0/...
  1226.  
  1227. 13. UNWIND-PROTECT:
  1228.  
  1229. (UNWIND-PROTECT-OPEN label)      baut einen UNWIND-PROTECT-Frame auf; bei einem
  1230.                                  Unwind wird unter Rettung der Werte zu label
  1231.                                  gesprungen
  1232.  
  1233. (UNWIND-PROTECT-NORMAL-EXIT)     löst einen Unwind-Protect-Frame auf, schreibt
  1234.                                  eine Weitermach-Adresse auf SP, rettet die
  1235.                                  Werte und fängt an, den folgenden Cleanup-Code
  1236.                                  auszuführen
  1237.  
  1238. (UNWIND-PROTECT-CLOSE label)     beendet den Cleanup-Code: schreibt die
  1239.                                  geretteten Werte zurück, führt ein RTS aus.
  1240.                                  Der Cleanup-Code fängt bei label an.
  1241.  
  1242. (UNWIND-PROTECT-CLEANUP)         löst einen Unwind-Protect-Frame auf, schreibt
  1243.                                  eine Weitermach-Adresse und den PC auf SP,
  1244.                                  rettet die Werte und fängt an, den Cleanup-
  1245.                                  Code auszuführen
  1246.  
  1247. 14. einige Funktionen:
  1248.  
  1249. (NOT)                            = (CALL1 #'NOT)
  1250.  
  1251. (EQ)                             = (CALL2 #'EQ)
  1252.  
  1253. (CAR)                            = (CALL1 #'CAR)
  1254.  
  1255. (CDR)                            = (CALL1 #'CDR)
  1256.  
  1257. (CONS)                           = (CALL2 #'CONS)
  1258.  
  1259. (ATOM)                           = (CALL1 #'ATOM)
  1260.  
  1261. (CONSP)                          = (CALL1 #'CONSP)
  1262.  
  1263. (SYMBOL-FUNCTION)                = (CALL1 #'SYMBOL-FUNCTION)
  1264.  
  1265. (SVREF)                          = (CALL2 #'SVREF)
  1266.  
  1267. (SVSET)                          (setf (svref (STACK) A0) (STACK+4)),
  1268.                                  A0 := (STACK+4), 1 Wert, STACK:=STACK+8
  1269.  
  1270. (LIST n)                         = (CALL n #'LIST), n>0
  1271.  
  1272. (LIST* n)                        = (CALL n+1 #'LIST*), n>0
  1273.  
  1274. (ERROR n)                        = (CALL n+1 #'ERROR)
  1275.  
  1276.  
  1277. Dabei bedeuten jeweils:
  1278.  
  1279. n, m, k     eine ganze Zahl >=0
  1280.  
  1281. stackz      einen Stackzustand (siehe STACK-VERWALTUNG).
  1282.             Das Stack-Layout steht nach dem 1. Pass fest.
  1283.  
  1284. venvc       das Environment der Closure-Variablen (siehe VARIABLEN-VERWALTUNG).
  1285.             Dies steht nach dem 1. Pass auch fest.
  1286.  
  1287. var         eine Variable (siehe VARIABLEN-VERWALTUNG). Ob sie
  1288.             special/konstant/lexikalisch ist, steht nach dem 1. Pass fest.
  1289.  
  1290. const       eine Konstante
  1291.  
  1292. symbol      ein Symbol
  1293.  
  1294. fun         entweder (CONST const) eine Konstante, die ein Symbol ist,
  1295.             oder (FUNTAB index) eine Indizierung in die feste Funktionentabelle.
  1296.  
  1297. fnode       ein fnode (siehe FUNKTIONEN-VERWALTUNG)
  1298.  
  1299. label       ein Label (uninterniertes Symbol)
  1300.  
  1301. block       ein Block-Descriptor (siehe BLOCK-VERWALTUNG)
  1302.  
  1303. test        EQ oder EQL oder EQUAL
  1304.  
  1305. for-value   NIL oder T
  1306.  
  1307. |#
  1308.  
  1309. #-CLISP ; Die Funktionentabelle steckt in EVAL.
  1310. (eval-when (compile load eval)
  1311.   ; die Funktionstabelle mit max. 3*256 Funktionen (spart Konstanten in FUNC) :
  1312.   (defconstant funtab
  1313.     '#(system::%funtabref system::subr-info
  1314.        #| svref system::%svstore |# array-element-type array-rank array-dimension
  1315.        array-dimensions array-total-size adjustable-array-p bit-and bit-ior
  1316.        bit-xor bit-eqv bit-nand bit-nor bit-andc1 bit-andc2 bit-orc1 bit-orc2
  1317.        bit-not array-has-fill-pointer-p fill-pointer system::set-fill-pointer
  1318.        vector-push vector-pop vector-push-extend make-array adjust-array
  1319.        standard-char-p graphic-char-p string-char-p alpha-char-p upper-case-p
  1320.        lower-case-p both-case-p digit-char-p alphanumericp char-code char-bits
  1321.        char-font code-char make-char character char-upcase char-downcase
  1322.        digit-char char-int int-char char-name char-bit set-char-bit char schar
  1323.        system::store-char system::store-schar string= string/= string< string>
  1324.        string<= string>= string-equal string-not-equal string-lessp
  1325.        string-greaterp string-not-greaterp string-not-lessp
  1326.        system::search-string= system::search-string-equal make-string
  1327.        system::string-both-trim nstring-upcase string-upcase nstring-downcase
  1328.        string-downcase nstring-capitalize string-capitalize string name-char
  1329.        substring
  1330.        symbol-value #| symbol-function |# boundp fboundp special-form-p set makunbound
  1331.        fmakunbound #| values-list |# system::driver system::unwind-to-driver
  1332.        macro-function macroexpand macroexpand-1 proclaim eval evalhook applyhook
  1333.        constantp system::parse-body system::keyword-test
  1334.        room
  1335.        make-hash-table gethash system::puthash remhash maphash clrhash
  1336.        hash-table-count system::hash-table-iterator system::hash-table-iterate
  1337.        sxhash
  1338.        copy-readtable set-syntax-from-char set-macro-character
  1339.        get-macro-character make-dispatch-macro-character
  1340.        set-dispatch-macro-character get-dispatch-macro-character read
  1341.        read-preserving-whitespace read-delimited-list read-line read-char
  1342.        unread-char peek-char listen read-char-no-hang clear-input
  1343.        read-from-string parse-integer write prin1 print pprint princ
  1344.        write-to-string prin1-to-string princ-to-string write-char write-string
  1345.        write-line terpri fresh-line finish-output force-output clear-output
  1346.        system::line-position
  1347.        #| car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar
  1348.        cdddr caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr cdaaar
  1349.        cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr cons |# tree-equal endp
  1350.        list-length nth #| first second third fourth |# fifth sixth seventh eighth
  1351.        ninth tenth #| rest |# nthcdr last make-list copy-list copy-alist copy-tree
  1352.        revappend nreconc system::list-nreverse butlast nbutlast ldiff rplaca
  1353.        system::%rplaca rplacd system::%rplacd subst subst-if subst-if-not nsubst
  1354.        nsubst-if nsubst-if-not sublis nsublis member member-if member-if-not
  1355.        tailp adjoin acons pairlis assoc assoc-if assoc-if-not rassoc rassoc-if
  1356.        rassoc-if-not
  1357.        lisp-implementation-type lisp-implementation-version software-type
  1358.        software-version identity get-universal-time get-internal-run-time
  1359.        get-internal-real-time system::%sleep system::%%time
  1360.        make-symbol find-package package-name package-nicknames rename-package
  1361.        package-use-list package-used-by-list package-shadowing-symbols
  1362.        list-all-packages intern find-symbol unintern export unexport import
  1363.        shadowing-import shadow use-package unuse-package make-package in-package
  1364.        find-all-symbols system::map-symbols system::map-external-symbols
  1365.        system::map-all-symbols
  1366.        parse-namestring pathname pathname-host pathname-device
  1367.        pathname-directory pathname-name pathname-type pathname-version
  1368.        file-namestring directory-namestring host-namestring merge-pathnames
  1369.        enough-namestring make-pathname namestring truename probe-file
  1370.        delete-file rename-file open directory cd make-dir delete-dir
  1371.        file-write-date file-author savemem
  1372.        #| eq |# eql equal equalp consp atom symbolp stringp numberp
  1373.        compiled-function-p #| null not |# system::closurep listp integerp
  1374.        system::fixnump rationalp floatp system::short-float-p
  1375.        system::single-float-p system::double-float-p system::long-float-p
  1376.        realp complexp streamp random-state-p readtablep hash-table-p pathnamep
  1377.        characterp functionp clos::generic-function-p packagep arrayp
  1378.        system::simple-array-p bit-vector-p vectorp simple-vector-p
  1379.        simple-string-p simple-bit-vector-p commonp type-of clos:class-of coerce
  1380.        system::%record-ref system::%record-store system::%record-length
  1381.        system::%structure-ref system::%structure-store system::%make-structure
  1382.        system::%copy-structure system::%structure-type-p system::closure-name
  1383.        system::closure-codevec system::closure-consts system::make-code-vector
  1384.        system::%make-closure system::make-load-time-eval clos::std-instance-p
  1385.        clos::allocate-std-instance clos:slot-value clos::set-slot-value
  1386.        clos:slot-boundp clos:slot-makunbound clos:slot-exists-p
  1387.        system::sequencep elt system::%setelt subseq copy-seq length reverse
  1388.        nreverse make-sequence reduce fill replace remove remove-if remove-if-not
  1389.        delete delete-if delete-if-not remove-duplicates delete-duplicates
  1390.        substitute substitute-if substitute-if-not nsubstitute nsubstitute-if
  1391.        nsubstitute-if-not find find-if find-if-not position position-if
  1392.        position-if-not count count-if count-if-not mismatch search sort
  1393.        stable-sort merge
  1394.        make-synonym-stream make-two-way-stream make-echo-stream
  1395.        make-string-input-stream system::string-input-stream-index
  1396.        make-string-output-stream get-output-stream-string
  1397.        system::make-string-push-stream input-stream-p output-stream-p
  1398.        stream-element-type close read-byte write-byte file-position file-length
  1399.        system::%putd system::%proclaim-constant get getf get-properties
  1400.        system::%putplist system::%put remprop symbol-package symbol-plist
  1401.        symbol-name keywordp gensym system::special-variable-p gensym
  1402.        system::decimal-string zerop plusp minusp oddp evenp 1+ 1- conjugate exp
  1403.        expt log sqrt isqrt abs phase signum sin cos tan cis asin acos atan sinh
  1404.        cosh tanh asinh acosh atanh float rational rationalize numerator
  1405.        denominator floor ceiling truncate round mod rem ffloor fceiling
  1406.        ftruncate fround decode-float scale-float float-radix float-sign
  1407.        float-digits float-precision integer-decode-float complex realpart
  1408.        imagpart lognand lognor logandc1 logandc2 logorc1 logorc2 boole lognot
  1409.        logtest logbitp ash logcount integer-length byte byte-size byte-position
  1410.        ldb ldb-test mask-field dpb deposit-field random make-random-state !
  1411.        exquo long-float-digits system::%set-long-float-digits system::log2
  1412.        system::log10
  1413.        vector aref system::store array-in-bounds-p array-row-major-index bit
  1414.        sbit char= char/= char< char> char<= char>= char-equal char-not-equal
  1415.        char-lessp char-greaterp char-not-greaterp char-not-lessp string-concat
  1416.        apply system::%funcall funcall mapcar maplist mapc mapl mapcan mapcon
  1417.        values list list* append nconc error concatenate map some every notany
  1418.        notevery make-broadcast-stream make-concatenated-stream = /= < > <= >=
  1419.        max min + - * / gcd lcm logior logxor logand logeqv
  1420.   )   )
  1421.   (defun %funtabref (index)
  1422.     (if (and (<= 0 index) (< index (length funtab))) (svref funtab index) nil)
  1423.   )
  1424. )
  1425. #+CROSS
  1426. (eval-when (compile load eval)
  1427.   (defun subr-info (sym)
  1428.     (values-list
  1429.       (assoc sym
  1430.         '(; Das ist die Tabelle aller SUBRs, wie in SUBR.D.
  1431.           ; SUBRs, die in verschiedenen Implementationen verschiedene
  1432.           ; Signaturen haben und/oder deren Spezifikation sich noch ändern
  1433.           ; könnte, sind dabei allerdings auskommentiert.
  1434.           (! 1 0 nil nil nil)
  1435.           (system::%%time 0 0 nil nil nil)
  1436.           (system::%copy-structure 1 0 nil nil nil)
  1437.           (system::%defseq 1 0 nil nil nil)
  1438.           (system::%exit 0 0 nil nil nil)
  1439.           (system::%funcall 1 0 t nil nil)
  1440.           (system::%funtabref 1 0 nil nil nil)
  1441.           (system::%make-closure 3 0 nil nil nil)
  1442.           (system::%make-structure 2 0 nil nil nil)
  1443.           (system::%proclaim-constant 2 0 nil nil nil)
  1444.           (system::%put 3 0 nil nil nil)
  1445.           (system::%putd 2 0 nil nil nil)
  1446.           (system::%putplist 2 0 nil nil nil)
  1447.           (system::%record-length 1 0 nil nil nil)
  1448.           (system::%record-ref 2 0 nil nil nil)
  1449.           (system::%record-store 3 0 nil nil nil)
  1450.           (system::%rplaca 2 0 nil nil nil)
  1451.           (system::%rplacd 2 0 nil nil nil)
  1452.           (system::%set-long-float-digits 1 0 nil nil nil)
  1453.           (system::%setelt 3 0 nil nil nil)
  1454.           ;(system::%sleep 1 0 nil nil nil)
  1455.           ;(system::%sleep 2 0 nil nil nil)
  1456.           (system::%structure-ref 3 0 nil nil nil)
  1457.           (system::%structure-store 4 0 nil nil nil)
  1458.           (system::%structure-type-p 2 0 nil nil nil)
  1459.           (system::%svstore 3 0 nil nil nil)
  1460.           (* 0 0 t nil nil)
  1461.           (+ 0 0 t nil nil)
  1462.           (- 1 0 t nil nil)
  1463.           (/ 1 0 t nil nil)
  1464.           (/= 1 0 t nil nil)
  1465.           (1+ 1 0 nil nil nil)
  1466.           (1- 1 0 nil nil nil)
  1467.           (< 1 0 t nil nil)
  1468.           (<= 1 0 t nil nil)
  1469.           (= 1 0 t nil nil)
  1470.           (> 1 0 t nil nil)
  1471.           (>= 1 0 t nil nil)
  1472.           (abs 1 0 nil nil nil)
  1473.           (acons 3 0 nil nil nil)
  1474.           (acos 1 0 nil nil nil)
  1475.           (acosh 1 0 nil nil nil)
  1476.           (adjoin 2 0 nil (:test :test-not :key) nil)
  1477.           (adjust-array 2 0 nil (:element-type :initial-element :initial-contents :fill-pointer :displaced-to :displaced-index-offset) nil)
  1478.           (adjustable-array-p 1 0 nil nil nil)
  1479.           (alpha-char-p 1 0 nil nil nil)
  1480.           (alphanumericp 1 0 nil nil nil)
  1481.           (append 0 0 t nil nil)
  1482.           (apply 2 0 t nil nil)
  1483.           (applyhook 4 1 nil nil nil)
  1484.           (aref 1 0 t nil nil)
  1485.           (array-dimension 2 0 nil nil nil)
  1486.           (array-dimensions 1 0 nil nil nil)
  1487.           (array-element-type 1 0 nil nil nil)
  1488.           (array-has-fill-pointer-p 1 0 nil nil nil)
  1489.           (array-in-bounds-p 1 0 t nil nil)
  1490.           (array-rank 1 0 nil nil nil)
  1491.           (system::array-reader 3 0 nil nil nil)
  1492.           (array-row-major-index 1 0 t nil nil)
  1493.           (array-total-size 1 0 nil nil nil)
  1494.           (arrayp 1 0 nil nil nil)
  1495.           (ash 2 0 nil nil nil)
  1496.           (asin 1 0 nil nil nil)
  1497.           (asinh 1 0 nil nil nil)
  1498.           (assoc 2 0 nil (:test :test-not :key) nil)
  1499.           (assoc-if 2 0 nil (:key) nil)
  1500.           (assoc-if-not 2 0 nil (:key) nil)
  1501.           (atan 1 1 nil nil nil)
  1502.           (atanh 1 0 nil nil nil)
  1503.           (atom 1 0 nil nil nil)
  1504.           (system::binary-reader 3 0 nil nil nil)
  1505.           (bit 1 0 t nil nil)
  1506.           (bit-and 2 1 nil nil nil)
  1507.           (bit-andc1 2 1 nil nil nil)
  1508.           (bit-andc2 2 1 nil nil nil)
  1509.           (bit-eqv 2 1 nil nil nil)
  1510.           (bit-ior 2 1 nil nil nil)
  1511.           (bit-nand 2 1 nil nil nil)
  1512.           (bit-nor 2 1 nil nil nil)
  1513.           (bit-not 1 1 nil nil nil)
  1514.           (bit-orc1 2 1 nil nil nil)
  1515.           (bit-orc2 2 1 nil nil nil)
  1516.           (bit-vector-p 1 0 nil nil nil)
  1517.           (system::bit-vector-reader 3 0 nil nil nil)
  1518.           (bit-xor 2 1 nil nil nil)
  1519.           (boole 3 0 nil nil nil)
  1520.           (both-case-p 1 0 nil nil nil)
  1521.           (boundp 1 0 nil nil nil)
  1522.           (butlast 1 1 nil nil nil)
  1523.           (byte 2 0 nil nil nil)
  1524.           (byte-position 1 0 nil nil nil)
  1525.           (byte-size 1 0 nil nil nil)
  1526.           (caaaar 1 0 nil nil nil)
  1527.           (caaadr 1 0 nil nil nil)
  1528.           (caaar 1 0 nil nil nil)
  1529.           (caadar 1 0 nil nil nil)
  1530.           (caaddr 1 0 nil nil nil)
  1531.           (caadr 1 0 nil nil nil)
  1532.           (caar 1 0 nil nil nil)
  1533.           (cadaar 1 0 nil nil nil)
  1534.           (cadadr 1 0 nil nil nil)
  1535.           (cadar 1 0 nil nil nil)
  1536.           (caddar 1 0 nil nil nil)
  1537.           (cadddr 1 0 nil nil nil)
  1538.           (caddr 1 0 nil nil nil)
  1539.           (cadr 1 0 nil nil nil)
  1540.           (car 1 0 nil nil nil)
  1541.           (cd 0 1 nil nil nil)
  1542.           (cdaaar 1 0 nil nil nil)
  1543.           (cdaadr 1 0 nil nil nil)
  1544.           (cdaar 1 0 nil nil nil)
  1545.           (cdadar 1 0 nil nil nil)
  1546.           (cdaddr 1 0 nil nil nil)
  1547.           (cdadr 1 0 nil nil nil)
  1548.           (cdar 1 0 nil nil nil)
  1549.           (cddaar 1 0 nil nil nil)
  1550.           (cddadr 1 0 nil nil nil)
  1551.           (cddar 1 0 nil nil nil)
  1552.           (cdddar 1 0 nil nil nil)
  1553.           (cddddr 1 0 nil nil nil)
  1554.           (cdddr 1 0 nil nil nil)
  1555.           (cddr 1 0 nil nil nil)
  1556.           (cdr 1 0 nil nil nil)
  1557.           (ceiling 1 1 nil nil nil)
  1558.           (char 2 0 nil nil nil)
  1559.           (char-bit 2 0 nil nil nil)
  1560.           (char-bits 1 0 nil nil nil)
  1561.           (char-code 1 0 nil nil nil)
  1562.           (char-downcase 1 0 nil nil nil)
  1563.           (char-equal 1 0 t nil nil)
  1564.           (char-font 1 0 nil nil nil)
  1565.           (char-greaterp 1 0 t nil nil)
  1566.           (char-int 1 0 nil nil nil)
  1567.           (char-lessp 1 0 t nil nil)
  1568.           (char-name 1 0 nil nil nil)
  1569.           (char-not-equal 1 0 t nil nil)
  1570.           (char-not-greaterp 1 0 t nil nil)
  1571.           (char-not-lessp 1 0 t nil nil)
  1572.           (system::char-reader 3 0 nil nil nil)
  1573.           (char-upcase 1 0 nil nil nil)
  1574.           (char/= 1 0 t nil nil)
  1575.           (char< 1 0 t nil nil)
  1576.           (char<= 1 0 t nil nil)
  1577.           (char= 1 0 t nil nil)
  1578.           (char> 1 0 t nil nil)
  1579.           (char>= 1 0 t nil nil)
  1580.           (character 1 0 nil nil nil)
  1581.           (characterp 1 0 nil nil nil)
  1582.           (cis 1 0 nil nil nil)
  1583.           (clos:class-of 1 0 nil nil nil)
  1584.           (clos::class-p 1 0 nil nil nil)
  1585.           (clear-input 0 1 nil nil nil)
  1586.           (clear-output 0 1 nil nil nil)
  1587.           (close 1 0 nil (:abort) nil)
  1588.           (system::closure-codevec 1 0 nil nil nil)
  1589.           (system::closure-consts 1 0 nil nil nil)
  1590.           (system::closure-name 1 0 nil nil nil)
  1591.           (system::closure-reader 3 0 nil nil nil)
  1592.           (system::closurep 1 0 nil nil nil)
  1593.           (clrhash 1 0 nil nil nil)
  1594.           (code-char 1 2 nil nil nil)
  1595.           (coerce 2 0 nil nil nil)
  1596.           (system::comment-reader 3 0 nil nil nil)
  1597.           (commonp 1 0 nil nil nil)
  1598.           (compiled-function-p 1 0 nil nil nil)
  1599.           (complex 1 1 nil nil nil)
  1600.           (system::complex-reader 3 0 nil nil nil)
  1601.           (complexp 1 0 nil nil nil)
  1602.           (concatenate 1 0 t nil nil)
  1603.           (conjugate 1 0 nil nil nil)
  1604.           (cons 2 0 nil nil nil)
  1605.           (consp 1 0 nil nil nil)
  1606.           (constantp 1 0 nil nil nil)
  1607.           (copy-alist 1 0 nil nil nil)
  1608.           (copy-list 1 0 nil nil nil)
  1609.           (copy-readtable 0 2 nil nil nil)
  1610.           (copy-seq 1 0 nil nil nil)
  1611.           (copy-tree 1 0 nil nil nil)
  1612.           (cos 1 0 nil nil nil)
  1613.           (cosh 1 0 nil nil nil)
  1614.           (count 2 0 nil (:from-end :start :end :key :test :test-not) nil)
  1615.           (count-if 2 0 nil (:from-end :start :end :key) nil)
  1616.           (count-if-not 2 0 nil (:from-end :start :end :key) nil)
  1617.           (system::debug 0 0 nil nil nil)
  1618.           (system::decimal-string 1 0 nil nil nil)
  1619.           (decode-float 1 0 nil nil nil)
  1620.           (delete 2 0 nil (:from-end :start :end :key :test :test-not :count) nil)
  1621.           (delete-dir 1 0 nil nil nil)
  1622.           (delete-duplicates 1 0 nil (:from-end :start :end :key :test :test-not) nil)
  1623.           (delete-file 1 0 nil nil nil)
  1624.           (delete-if 2 0 nil (:from-end :start :end :key :count) nil)
  1625.           (delete-if-not 2 0 nil (:from-end :start :end :key :count) nil)
  1626.           (denominator 1 0 nil nil nil)
  1627.           (deposit-field 3 0 nil nil nil)
  1628.           (system::describe-frame 2 0 nil nil nil)
  1629.           (digit-char 1 2 nil nil nil)
  1630.           (digit-char-p 1 1 nil nil nil)
  1631.           (directory 0 1 nil (:full) nil)
  1632.           (directory-namestring 1 0 nil nil nil)
  1633.           (system::double-float-p 1 0 nil nil nil)
  1634.           (dpb 3 0 nil nil nil)
  1635.           (system::driver 1 0 nil nil nil)
  1636.           (eighth 1 0 nil nil nil)
  1637.           (elt 2 0 nil nil nil)
  1638.           (endp 1 0 nil nil nil)
  1639.           (enough-namestring 1 1 nil nil nil)
  1640.           (eq 2 0 nil nil nil)
  1641.           (eql 2 0 nil nil nil)
  1642.           (equal 2 0 nil nil nil)
  1643.           (equalp 2 0 nil nil nil)
  1644.           (error 1 0 t nil nil)
  1645.           (eval 1 0 nil nil nil)
  1646.           (system::eval-at 2 0 nil nil nil)
  1647.           (system::eval-frame-p 1 0 nil nil nil)
  1648.           (evalhook 3 1 nil nil nil)
  1649.           (evenp 1 0 nil nil nil)
  1650.           (every 2 0 t nil nil)
  1651.           ;(execute 1 2 nil nil nil)
  1652.           ;(execute 1 0 t nil nil)
  1653.           (exp 1 0 nil nil nil)
  1654.           (export 1 1 nil nil nil)
  1655.           (expt 2 0 nil nil nil)
  1656.           (exquo 2 0 nil nil nil)
  1657.           (fboundp 1 0 nil nil nil)
  1658.           (fceiling 1 1 nil nil nil)
  1659.           (system::feature-reader 3 0 nil nil nil)
  1660.           (ffloor 1 1 nil nil nil)
  1661.           (fifth 1 0 nil nil nil)
  1662.           (file-author 1 0 nil nil nil)
  1663.           (file-length 1 0 nil nil nil)
  1664.           (file-namestring 1 0 nil nil nil)
  1665.           (file-position 1 1 nil nil nil)
  1666.           (file-write-date 1 0 nil nil nil)
  1667.           (fill 2 0 nil (:start :end) nil)
  1668.           (fill-pointer 1 0 nil nil nil)
  1669.           (find 2 0 nil (:from-end :start :end :key :test :test-not) nil)
  1670.           (find-all-symbols 1 0 nil nil nil)
  1671.           (find-if 2 0 nil (:from-end :start :end :key) nil)
  1672.           (find-if-not 2 0 nil (:from-end :start :end :key) nil)
  1673.           (find-package 1 0 nil nil nil)
  1674.           (find-symbol 1 1 nil nil nil)
  1675.           (finish-output 0 1 nil nil nil)
  1676.           (first 1 0 nil nil nil)
  1677.           (system::fixnump 1 0 nil nil nil)
  1678.           (float 1 1 nil nil nil)
  1679.           (float-digits 1 1 nil nil nil)
  1680.           (float-precision 1 0 nil nil nil)
  1681.           (float-radix 1 0 nil nil nil)
  1682.           (float-sign 1 1 nil nil nil)
  1683.           (floatp 1 0 nil nil nil)
  1684.           (floor 1 1 nil nil nil)
  1685.           (fmakunbound 1 0 nil nil nil)
  1686.           (force-output 0 1 nil nil nil)
  1687.           (fourth 1 0 nil nil nil)
  1688.           (system::frame-down 2 0 nil nil nil)
  1689.           (system::frame-down-1 2 0 nil nil nil)
  1690.           (system::frame-up 2 0 nil nil nil)
  1691.           (system::frame-up-1 2 0 nil nil nil)
  1692.           (fresh-line 0 1 nil nil nil)
  1693.           (fround 1 1 nil nil nil)
  1694.           (ftruncate 1 1 nil nil nil)
  1695.           (funcall 1 0 t nil nil)
  1696.           (system::function-reader 3 0 nil nil nil)
  1697.           (functionp 1 0 nil nil nil)
  1698.           (gc 0 0 nil nil nil)
  1699.           (gcd 0 0 t nil nil)
  1700.           (clos::generic-function-p 1 0 nil nil nil)
  1701.           (gensym 0 1 nil nil nil)
  1702.           (get 2 1 nil nil nil)
  1703.           (get-dispatch-macro-character 2 1 nil nil nil)
  1704.           (get-internal-real-time 0 0 nil nil nil)
  1705.           (get-internal-run-time 0 0 nil nil nil)
  1706.           (get-macro-character 1 1 nil nil nil)
  1707.           (get-output-stream-string 1 0 nil nil nil)
  1708.           (get-properties 2 0 nil nil nil)
  1709.           (get-universal-time 0 0 nil nil nil)
  1710.           (getf 2 1 nil nil nil)
  1711.           (gethash 2 1 nil nil nil)
  1712.           (graphic-char-p 1 0 nil nil nil)
  1713.           (hash-table-count 1 0 nil nil nil)
  1714.           (system::hash-table-iterate 1 0 nil nil nil)
  1715.           (system::hash-table-iterator 1 0 nil nil nil)
  1716.           (hash-table-p 1 0 nil nil nil)
  1717.           (system::hexadecimal-reader 3 0 nil nil nil)
  1718.           (host-namestring 1 0 nil nil nil)
  1719.           (identity 1 0 nil nil nil)
  1720.           (imagpart 1 0 nil nil nil)
  1721.           (import 1 1 nil nil nil)
  1722.           (in-package 1 0 nil (:nicknames :use) nil)
  1723.           (system::initial-contents-aux 1 0 nil nil nil)
  1724.           (input-stream-p 1 0 nil nil nil)
  1725.           (int-char 1 0 nil nil nil)
  1726.           (integer-decode-float 1 0 nil nil nil)
  1727.           (integer-length 1 0 nil nil nil)
  1728.           (integerp 1 0 nil nil nil)
  1729.           (intern 1 1 nil nil nil)
  1730.           (isqrt 1 0 nil nil nil)
  1731.           (system::keyword-test 2 0 nil nil nil)
  1732.           (keywordp 1 0 nil nil nil)
  1733.           (system::label-definiion-reader 3 0 nil nil nil)
  1734.           (system::label-reference-reader 3 0 nil nil nil)
  1735.           (last 1 0 nil nil nil)
  1736.           (lcm 0 0 t nil nil)
  1737.           (ldb 2 0 nil nil nil)
  1738.           (ldb-test 2 0 nil nil nil)
  1739.           (ldiff 2 0 nil nil nil)
  1740.           (length 1 0 nil nil nil)
  1741.           (system::line-comment-reader 2 0 nil nil nil)
  1742.           (system::line-position 0 1 nil nil nil)
  1743.           (lisp-implementation-type 0 0 nil nil nil)
  1744.           (lisp-implementation-version 0 0 nil nil nil)
  1745.           (list 0 0 t nil nil)
  1746.           (list* 1 0 t nil nil)
  1747.           (system::list-access 2 0 nil nil nil)
  1748.           (system::list-access-set 3 0 nil nil nil)
  1749.           (list-all-packages 0 0 nil nil nil)
  1750.           (system::list-elt 2 0 nil nil nil)
  1751.           (system::list-endtest 2 0 nil nil nil)
  1752.           (system::list-fe-init 1 0 nil nil nil)
  1753.           (system::list-fe-init-end 2 0 nil nil nil)
  1754.           (system::list-init-start 2 0 nil nil nil)
  1755.           (list-length 1 0 nil nil nil)
  1756.           (system::list-llength 1 0 nil nil nil)
  1757.           (system::list-nreverse 1 0 nil nil nil)
  1758.           (system::list-set-elt 3 0 nil nil nil)
  1759.           (system::list-upd 2 0 nil nil nil)
  1760.           (listen 0 1 nil nil nil)
  1761.           (listp 1 0 nil nil nil)
  1762.           (system::load-eval-reader 3 0 nil nil nil)
  1763.           (log 1 1 nil nil nil)
  1764.           (system::log10 1 0 nil nil nil)
  1765.           (system::log2 1 0 nil nil nil)
  1766.           (logand 0 0 t nil nil)
  1767.           (logandc1 2 0 nil nil nil)
  1768.           (logandc2 2 0 nil nil nil)
  1769.           (logbitp 2 0 nil nil nil)
  1770.           (logcount 1 0 nil nil nil)
  1771.           (logeqv 0 0 t nil nil)
  1772.           (logior 0 0 t nil nil)
  1773.           (lognand 2 0 nil nil nil)
  1774.           (lognor 2 0 nil nil nil)
  1775.           (lognot 1 0 nil nil nil)
  1776.           (logorc1 2 0 nil nil nil)
  1777.           (logorc2 2 0 nil nil nil)
  1778.           (logtest 2 0 nil nil nil)
  1779.           (logxor 0 0 t nil nil)
  1780.           (long-float-digits 0 0 nil nil nil)
  1781.           (system::long-float-p 1 0 nil nil nil)
  1782.           (lower-case-p 1 0 nil nil nil)
  1783.           (system::lpar-reader 2 0 nil nil nil)
  1784.           ;(machine-instance 0 0 nil nil nil)
  1785.           ;(machine-type 0 0 nil nil nil)
  1786.           ;(machine-version 0 0 nil nil nil)
  1787.           (macro-function 1 0 nil nil nil)
  1788.           (macroexpand 1 1 nil nil nil)
  1789.           (macroexpand-1 1 1 nil nil nil)
  1790.           (make-array 1 0 nil (:adjustable :element-type :initial-element :initial-contents :fill-pointer :displaced-to :displaced-index-offset) nil)
  1791.           (system::make-bit-vector 1 0 nil nil nil)
  1792.           (make-broadcast-stream 0 0 t nil nil)
  1793.           (make-buffered-input-stream 2 0 nil nil nil)
  1794.           (make-buffered-output-stream 1 0 nil nil nil)
  1795.           (make-char 1 2 nil nil nil)
  1796.           (system::make-code-vector 1 0 nil nil nil)
  1797.           (make-concatenated-stream 0 0 t nil nil)
  1798.           (make-dir 1 0 nil nil nil)
  1799.           (make-dispatch-macro-character 1 2 nil nil nil)
  1800.           (make-echo-stream 2 0 nil nil nil)
  1801.           (make-hash-table 0 0 nil (:initial-contents :test :size :rehash-size :rehash-threshold) nil)
  1802.           (make-list 1 0 nil (:initial-element) nil)
  1803.           (system::make-load-time-eval 1 0 nil nil nil)
  1804.           (make-package 1 0 nil (:nicknames :use) nil)
  1805.           (make-pathname 0 0 nil (:defaults :host :device :directory :name :type :version) nil)
  1806.           #+UNIX (make-pipe-input-stream 1 0 nil nil nil)
  1807.           #+UNIX (make-pipe-output-stream 1 0 nil nil nil)
  1808.           (make-random-state 0 1 nil nil nil)
  1809.           (make-sequence 2 0 nil (:initial-element :update) nil)
  1810.           (make-string 1 0 nil (:initial-element) nil)
  1811.           (make-string-input-stream 1 2 nil nil nil)
  1812.           (make-string-output-stream 0 1 nil nil nil)
  1813.           (system::make-string-push-stream 1 0 nil nil nil)
  1814.           (make-symbol 1 0 nil nil nil)
  1815.           (make-synonym-stream 1 0 nil nil nil)
  1816.           (make-two-way-stream 2 0 nil nil nil)
  1817.           (makunbound 1 0 nil nil nil)
  1818.           (map 3 0 t nil nil)
  1819.           (system::map-all-symbols 1 0 nil nil nil)
  1820.           (system::map-external-symbols 2 0 nil nil nil)
  1821.           (system::map-symbols 2 0 nil nil nil)
  1822.           (mapc 2 0 t nil nil)
  1823.           (mapcan 2 0 t nil nil)
  1824.           (mapcar 2 0 t nil nil)
  1825.           (mapcon 2 0 t nil nil)
  1826.           (maphash 2 0 nil nil nil)
  1827.           (mapl 2 0 t nil nil)
  1828.           (maplist 2 0 t nil nil)
  1829.           (mask-field 2 0 nil nil nil)
  1830.           (max 1 0 t nil nil)
  1831.           (member 2 0 nil (:test :test-not :key) nil)
  1832.           (member-if 2 0 nil (:key) nil)
  1833.           (member-if-not 2 0 nil (:key) nil)
  1834.           (merge 4 0 nil (:key) nil)
  1835.           (merge-pathnames 1 2 nil nil nil)
  1836.           (min 1 0 t nil nil)
  1837.           (minusp 1 0 nil nil nil)
  1838.           (mismatch 2 0 nil (:from-end :start1 :end1 :start2 :end2 :key :test :test-not) nil)
  1839.           (mod 2 0 nil nil nil)
  1840.           (name-char 1 0 nil nil nil)
  1841.           #-ATARI (namestring 1 0 nil nil nil)
  1842.           #+ATARI (namestring 1 1 nil nil nil)
  1843.           (nbutlast 1 1 nil nil nil)
  1844.           (nconc 0 0 t nil nil)
  1845.           (ninth 1 0 nil nil nil)
  1846.           (not 1 0 nil nil nil)
  1847.           (system::not-feature-reader 3 0 nil nil nil)
  1848.           (system::not-readable-reader 3 0 nil nil nil)
  1849.           (notany 2 0 t nil nil)
  1850.           (notevery 2 0 t nil nil)
  1851.           (nreconc 2 0 nil nil nil)
  1852.           (nreverse 1 0 nil nil nil)
  1853.           (nstring-capitalize 1 0 nil (:start :end) nil)
  1854.           (nstring-downcase 1 0 nil (:start :end) nil)
  1855.           (nstring-upcase 1 0 nil (:start :end) nil)
  1856.           (nsublis 2 0 nil (:test :test-not :key) nil)
  1857.           (nsubst 3 0 nil (:test :test-not :key) nil)
  1858.           (nsubst-if 3 0 nil (:key) nil)
  1859.           (nsubst-if-not 3 0 nil (:key) nil)
  1860.           (nsubstitute 3 0 nil (:from-end :start :end :key :test :test-not :count) nil)
  1861.           (nsubstitute-if 3 0 nil (:from-end :start :end :key :count) nil)
  1862.           (nsubstitute-if-not 3 0 nil (:from-end :start :end :key :count) nil)
  1863.           (nth 2 0 nil nil nil)
  1864.           (nthcdr 2 0 nil nil nil)
  1865.           (null 1 0 nil nil nil)
  1866.           (numberp 1 0 nil nil nil)
  1867.           (numerator 1 0 nil nil nil)
  1868.           (system::octal-reader 3 0 nil nil nil)
  1869.           (oddp 1 0 nil nil nil)
  1870.           (open 1 0 nil (:direction :element-type :if-exists :if-does-not-exist) nil)
  1871.           (output-stream-p 1 0 nil nil nil)
  1872.           (package-name 1 0 nil nil nil)
  1873.           (package-nicknames 1 0 nil nil nil)
  1874.           (package-shadowing-symbols 1 0 nil nil nil)
  1875.           (package-use-list 1 0 nil nil nil)
  1876.           (package-used-by-list 1 0 nil nil nil)
  1877.           (packagep 1 0 nil nil nil)
  1878.           (pairlis 2 1 nil nil nil)
  1879.           (system::parse-body 1 2 nil nil nil)
  1880.           (parse-integer 1 0 nil (:start :end :radix :junk-allowed) nil)
  1881.           (parse-namestring 1 2 nil (:start :end :junk-allowed) nil)
  1882.           (pathname 1 0 nil nil nil)
  1883.           (pathname-device 1 0 nil nil nil)
  1884.           (pathname-directory 1 0 nil nil nil)
  1885.           (pathname-host 1 0 nil nil nil)
  1886.           (pathname-name 1 0 nil nil nil)
  1887.           (system::pathname-reader 3 0 nil nil nil)
  1888.           (pathname-type 1 0 nil nil nil)
  1889.           (pathname-version 1 0 nil nil nil)
  1890.           (pathnamep 1 0 nil nil nil)
  1891.           (peek-char 0 5 nil nil nil)
  1892.           (phase 1 0 nil nil nil)
  1893.           (plusp 1 0 nil nil nil)
  1894.           (position 2 0 nil (:from-end :start :end :key :test :test-not) nil)
  1895.           (position-if 2 0 nil (:from-end :start :end :key) nil)
  1896.           (position-if-not 2 0 nil (:from-end :start :end :key) nil)
  1897.           (pprint 1 1 nil nil nil)
  1898.           (prin1 1 1 nil nil nil)
  1899.           (prin1-to-string 1 0 nil nil nil)
  1900.           (princ 1 1 nil nil nil)
  1901.           (princ-to-string 1 0 nil nil nil)
  1902.           (print 1 1 nil nil nil)
  1903.           (probe-file 1 0 nil nil nil)
  1904.           (proclaim 1 0 nil nil nil)
  1905.           (system::puthash 3 0 nil nil nil)
  1906.           (system::quote-reader 2 0 nil nil nil)
  1907.           (system::radix-reader 3 0 nil nil nil)
  1908.           (random 1 1 nil nil nil)
  1909.           (random-state-p 1 0 nil nil nil)
  1910.           (rassoc 2 0 nil (:test :test-not :key) nil)
  1911.           (rassoc-if 2 0 nil (:key) nil)
  1912.           (rassoc-if-not 2 0 nil (:key) nil)
  1913.           (rational 1 0 nil nil nil)
  1914.           (rationalize 1 0 nil nil nil)
  1915.           (rationalp 1 0 nil nil nil)
  1916.           (read 0 4 nil nil nil)
  1917.           (read-byte 1 2 nil nil nil)
  1918.           (read-char 0 4 nil nil nil)
  1919.           (read-char-no-hang 0 4 nil nil nil)
  1920.           (read-delimited-list 1 2 nil nil nil)
  1921.           (system::read-eval-print 1 1 nil nil nil)
  1922.           (system::read-eval-reader 3 0 nil nil nil)
  1923.           (system::read-form 1 1 nil nil nil)
  1924.           (read-from-string 1 2 nil (:preserve-whitespace :start :end) nil)
  1925.           (read-line 0 4 nil nil nil)
  1926.           (read-preserving-whitespace 0 4 nil nil nil)
  1927.           (readtablep 1 0 nil nil nil)
  1928.           (realp 1 0 nil nil nil)
  1929.           (realpart 1 0 nil nil nil)
  1930.           (system::redo-eval-frame 1 0 nil nil nil)
  1931.           (reduce 2 0 nil (:from-end :start :end :initial-value) nil)
  1932.           (rem 2 0 nil nil nil)
  1933.           (remhash 2 0 nil nil nil)
  1934.           (remove 2 0 nil (:from-end :start :end :key :test :test-not :count) nil)
  1935.           (remove-duplicates 1 0 nil (:from-end :start :end :key :test :test-not) nil)
  1936.           (remove-if 2 0 nil (:from-end :start :end :key :count) nil)
  1937.           (remove-if-not 2 0 nil (:from-end :start :end :key :count) nil)
  1938.           (remprop 2 0 nil nil nil)
  1939.           (rename-file 2 0 nil nil nil)
  1940.           (rename-package 2 1 nil nil nil)
  1941.           (replace 2 0 nil (:start1 :end1 :start2 :end2) nil)
  1942.           (rest 1 0 nil nil nil)
  1943.           (system::return-from-eval-frame 2 0 nil nil nil)
  1944.           (revappend 2 0 nil nil nil)
  1945.           (reverse 1 0 nil nil nil)
  1946.           (room 0 0 nil nil nil)
  1947.           (round 1 1 nil nil nil)
  1948.           (system::rpar-reader 2 0 nil nil nil)
  1949.           (rplaca 2 0 nil nil nil)
  1950.           (rplacd 2 0 nil nil nil)
  1951.           (system::same-env-as 2 0 nil nil nil)
  1952.           (savemem 1 0 nil nil nil)
  1953.           (sbit 1 0 t nil nil)
  1954.           (scale-float 2 0 nil nil nil)
  1955.           (schar 2 0 nil nil nil)
  1956.           (search 2 0 nil (:from-end :start1 :end1 :start2 :end2 :key :test :test-not) nil)
  1957.           (system::search-string-equal 2 0 nil (:start1 :end1 :start2 :end2) nil)
  1958.           (system::search-string= 2 0 nil (:start1 :end1 :start2 :end2) nil)
  1959.           (second 1 0 nil nil nil)
  1960.           (system::sequencep 1 0 nil nil nil)
  1961.           (set 2 0 nil nil nil)
  1962.           (set-char-bit 3 0 nil nil nil)
  1963.           (set-dispatch-macro-character 3 1 nil nil nil)
  1964.           (system::set-fill-pointer 2 0 nil nil nil)
  1965.           (set-macro-character 2 2 nil nil nil)
  1966.           (set-syntax-from-char 2 2 nil nil nil)
  1967.           (seventh 1 0 nil nil nil)
  1968.           (shadow 1 1 nil nil nil)
  1969.           (shadowing-import 1 1 nil nil nil)
  1970.           ;(shell 0 1 nil nil nil)
  1971.           (system::short-float-p 1 0 nil nil nil)
  1972.           (show-stack 0 0 nil nil nil)
  1973.           (signum 1 0 nil nil nil)
  1974.           (system::simple-array-p 1 0 nil nil nil)
  1975.           (simple-bit-vector-p 1 0 nil nil nil)
  1976.           (simple-string-p 1 0 nil nil nil)
  1977.           (simple-vector-p 1 0 nil nil nil)
  1978.           (sin 1 0 nil nil nil)
  1979.           (system::single-float-p 1 0 nil nil nil)
  1980.           (sinh 1 0 nil nil nil)
  1981.           (sixth 1 0 nil nil nil)
  1982.           (clos:slot-value 2 0 nil nil nil)
  1983.           (clos::set-slot-value 3 0 nil nil nil)
  1984.           (clos:slot-boundp 2 0 nil nil nil)
  1985.           (clos:slot-makunbound 2 0 nil nil nil)
  1986.           (clos:slot-exists-p 2 0 nil nil nil)
  1987.           (software-type 0 0 nil nil nil)
  1988.           (software-version 0 0 nil nil nil)
  1989.           (some 2 0 t nil nil)
  1990.           (sort 2 0 nil (:key :start :end) nil)
  1991.           (special-form-p 1 0 nil nil nil)
  1992.           (system::special-variable-p 1 0 nil nil nil)
  1993.           (sqrt 1 0 nil nil nil)
  1994.           (stable-sort 2 0 nil (:key :start :end) nil)
  1995.           (standard-char-p 1 0 nil nil nil)
  1996.           (system::store 2 0 t nil nil)
  1997.           (system::store-char 3 0 nil nil nil)
  1998.           (system::store-schar 3 0 nil nil nil)
  1999.           (stream-element-type 1 0 nil nil nil)
  2000.           (streamp 1 0 nil nil nil)
  2001.           (string 1 0 nil nil nil)
  2002.           (system::string-both-trim 3 0 nil nil nil)
  2003.           (string-capitalize 1 0 nil (:start :end) nil)
  2004.           (string-char-p 1 0 nil nil nil)
  2005.           (string-concat 0 0 t nil nil)
  2006.           (string-downcase 1 0 nil (:start :end) nil)
  2007.           (string-equal 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2008.           (string-greaterp 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2009.           (system::string-input-stream-index 1 0 nil nil nil)
  2010.           (string-lessp 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2011.           (string-not-equal 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2012.           (string-not-greaterp 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2013.           (string-not-lessp 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2014.           (system::string-reader 2 0 nil nil nil)
  2015.           (string-upcase 1 0 nil (:start :end) nil)
  2016.           (string/= 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2017.           (string< 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2018.           (string<= 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2019.           (string= 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2020.           (string> 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2021.           (string>= 2 0 nil (:start1 :end1 :start2 :end2) nil)
  2022.           (stringp 1 0 nil nil nil)
  2023.           (system::structure-reader 3 0 nil nil nil)
  2024.           (sublis 2 0 nil (:test :test-not :key) nil)
  2025.           (system::subr-info 1 0 nil nil nil)
  2026.           (subseq 2 1 nil nil nil)
  2027.           (subst 3 0 nil (:test :test-not :key) nil)
  2028.           (subst-if 3 0 nil (:key) nil)
  2029.           (subst-if-not 3 0 nil (:key) nil)
  2030.           (substitute 3 0 nil (:from-end :start :end :key :test :test-not :count) nil)
  2031.           (substitute-if 3 0 nil (:from-end :start :end :key :count) nil)
  2032.           (substitute-if-not 3 0 nil (:from-end :start :end :key :count) nil)
  2033.           (substring 2 1 nil nil nil)
  2034.           (svref 2 0 nil nil nil)
  2035.           (system::svstore 3 0 nil nil nil)
  2036.           (sxhash 1 0 nil nil nil)
  2037.           (symbol-function 1 0 nil nil nil)
  2038.           (symbol-name 1 0 nil nil nil)
  2039.           (symbol-package 1 0 nil nil nil)
  2040.           (symbol-plist 1 0 nil nil nil)
  2041.           (symbol-value 1 0 nil nil nil)
  2042.           (symbolp 1 0 nil nil nil)
  2043.           (system::syntax-error-reader 3 0 nil nil nil)
  2044.           (tailp 2 0 nil nil nil)
  2045.           (tan 1 0 nil nil nil)
  2046.           (tanh 1 0 nil nil nil)
  2047.           (tenth 1 0 nil nil nil)
  2048.           (terpri 0 1 nil nil nil)
  2049.           (system::the-frame 0 0 nil nil nil)
  2050.           (third 1 0 nil nil nil)
  2051.           (tree-equal 2 0 nil (:test :test-not) nil)
  2052.           (truename 1 0 nil nil nil)
  2053.           (truncate 1 1 nil nil nil)
  2054.           (type-of 1 0 nil nil nil)
  2055.           (unexport 1 1 nil nil nil)
  2056.           (unintern 1 1 nil nil nil)
  2057.           (system::uninterned-reader 3 0 nil nil nil)
  2058.           (unread-char 1 1 nil nil nil)
  2059.           (unuse-package 1 1 nil nil nil)
  2060.           (system::unwind-to-driver 0 0 nil nil nil)
  2061.           (upper-case-p 1 0 nil nil nil)
  2062.           (use-package 1 1 nil nil nil)
  2063.           (system::use-package-aux 1 0 nil nil nil)
  2064.           #+UNIX (user-homedir-pathname 0 1 nil nil nil)
  2065.           (values 0 0 t nil nil)
  2066.           (values-list 1 0 nil nil nil)
  2067.           (vector 0 0 t nil nil)
  2068.           (system::vector-endtest 2 0 nil nil nil)
  2069.           (system::vector-fe-endtest 2 0 nil nil nil)
  2070.           (system::vector-fe-init 1 0 nil nil nil)
  2071.           (system::vector-fe-init-end 2 0 nil nil nil)
  2072.           (system::vector-fe-upd 2 0 nil nil nil)
  2073.           (system::vector-init 1 0 nil nil nil)
  2074.           (system::vector-init-start 2 0 nil nil nil)
  2075.           (system::vector-length 1 0 nil nil nil)
  2076.           (vector-pop 1 0 nil nil nil)
  2077.           (vector-push 2 0 nil nil nil)
  2078.           (vector-push-extend 2 1 nil nil nil)
  2079.           (system::vector-reader 3 0 nil nil nil)
  2080.           (system::vector-upd 2 0 nil nil nil)
  2081.           (vectorp 1 0 nil nil nil)
  2082.           (system::version 0 1 nil nil nil)
  2083.           (write 1 0 nil (:case :level :length :gensym :escape :radix :base :array :circle :pretty :closure :stream) nil)
  2084.           (write-byte 2 0 nil nil nil)
  2085.           (write-char 1 1 nil nil nil)
  2086.           (write-line 1 1 nil (:start :end) nil)
  2087.           (write-string 1 1 nil (:start :end) nil)
  2088.           (write-to-string 1 0 nil (:case :level :length :gensym :escape :radix :base :array :circle :pretty :closure) nil)
  2089.           #-CLISP1 (xgcd 0 0 t nil nil)
  2090.           (zerop 1 0 nil nil nil)
  2091. ) ) ) )  )
  2092. (defconstant function-codes
  2093.   (let ((hashtable (make-hash-table :test #'eq)))
  2094.     (dotimes (i (* 3 256))
  2095.       (let ((sym (%funtabref i))) ; Name der Funktion FUNTAB[i]
  2096.         (when sym (setf (gethash sym hashtable) i))
  2097.     ) )
  2098.     hashtable
  2099. ) )
  2100. (defconstant funtabR-index ; Startindex der FUNTABR bzgl. FUNTAB
  2101.   (dotimes (i (* 3 256))
  2102.     (let ((sym (%funtabref i)))
  2103.       (multiple-value-bind (name req opt rest-p) (subr-info sym)
  2104.         (declare (ignore name req opt))
  2105.         (when rest-p (return i))
  2106. ) ) ) )
  2107. (defun CALLS-code (funtab-index)
  2108.   (if (< funtab-index 256)
  2109.     `(CALLS1 ,funtab-index)
  2110.     `(CALLS2 ,(- funtab-index 256))
  2111. ) )
  2112.  
  2113. ; Hilfsfunktion: mapcan, aber mit append statt nconc:
  2114. #|
  2115. #-CLISP
  2116. (defun mapcap (fun &rest lists &aux (L nil))
  2117.   (loop
  2118.     (setq L
  2119.       (nconc
  2120.         (reverse
  2121.           (apply fun
  2122.             (maplist #'(lambda (listsr)
  2123.                          (if (atom (car listsr))
  2124.                            (return)
  2125.                            (pop (car listsr))
  2126.                        ) )
  2127.                      lists
  2128.         ) ) )
  2129.         L
  2130.       )
  2131.   ) )
  2132.   (nreverse L)
  2133. )
  2134. |#
  2135. #-CLISP
  2136. (defun mapcap (fun &rest lists)
  2137.   (apply #'append (apply #'mapcar fun lists))
  2138. )
  2139.  
  2140. ; Hilfsfunktion: mapcon, aber mit append statt nconc:
  2141. #|
  2142. #-CLISP
  2143. (defun maplap (fun &rest lists &aux (L nil))
  2144.   (loop
  2145.     (setq L
  2146.       (nconc
  2147.         (reverse
  2148.           (apply fun
  2149.             (maplist #'(lambda (listsr)
  2150.                          (if (atom (car listsr))
  2151.                            (return)
  2152.                            (prog1
  2153.                              (car listsr)
  2154.                              (setf (car listsr) (cdr (car listsr)))
  2155.                        ) ) )
  2156.                      lists
  2157.         ) ) )
  2158.         L
  2159.       )
  2160.   ) )
  2161.   (nreverse L)
  2162. )
  2163. |#
  2164. #-CLISP
  2165. (defun maplap (fun &rest lists)
  2166.   (apply #'append (apply #'maplist fun lists))
  2167. )
  2168.  
  2169. ; (memq item const-symbollist) == (member item const-symbollist :test #'eq),
  2170. ; nur der boolesche Wert.
  2171. (defmacro memq (item list)
  2172.   (if (and (constantp list) (listp (eval list)))
  2173.     `(case ,item (,(eval list) t) (t nil))
  2174.     `(member ,item ,list :test #'eq)
  2175. ) )
  2176.  
  2177. ; Fehlermeldungsfunktion
  2178. (defun compiler-error (caller &optional where)
  2179.   (error #+DEUTSCH "Fehler im Compiler!! Aufgetreten in ~A~@[ bei ~A~]."
  2180.          #+ENGLISH "Compiler bug!! Occurred in ~A~@[ at ~A~]."
  2181.          caller where
  2182. ) )
  2183.  
  2184.  
  2185.  
  2186. ;                      S T A C K - V E R W A L T U N G
  2187.  
  2188. ; Ein Stackzustand beschreibt, was sich zur Laufzeit alles auf den beiden
  2189. ; Stacks befinden wird.
  2190. ; Genaue Struktur:
  2191. ; (item1 ... itemk . fun)
  2192. ; Das ist im Speicher in Wirklichkeit eine Baumstruktur!
  2193. ; Es bedeuten hierbei:
  2194. ;  fun = FNODE der Funktion, in der gezählt wird.
  2195. ;  item = eines der folgenden:
  2196. ;    n (Integer >=0) : n Lisp-Objekte auf dem STACK
  2197. ;                      belegt n STACK-Einträge
  2198. ;    (BIND n)        : einen Bindungsframe für n Variablen,
  2199. ;                      belegt 1+2*n STACK-Einträge und 0 SP-Einträge
  2200. ;                      Muß bei Unwind explizit aufgelöst werden
  2201. ;    PROGV           : ein Bindungsframe für beliebig viele Variablen,
  2202. ;                      belegt ? STACK-Einträge und 1 SP-Eintrag (Pointer über
  2203. ;                      den Frame = alter STACK)
  2204. ;                      Muß bei Unwind explizit aufgelöst werden
  2205. ;    CATCH           : ein CATCH-Frame
  2206. ;                      belegt 3 STACK-Einträge und 2+*jmpbuf-size* SP-Einträge
  2207. ;    UNWIND-PROTECT  : ein Unwind-Protect-Frame
  2208. ;                      belegt 2 STACK-Einträge und 2+*jmpbuf-size* SP-Einträge
  2209. ;                      Muß bei Unwind aufgelöst und der Cleanup ausgeführt
  2210. ;                      werden
  2211. ;    CLEANUP         : während der Cleanup-Phase eines UNWIND-PROTECT
  2212. ;                      belegt ? STACK-Einträge und 3 SP-Einträge
  2213. ;                      (der untere ist Pointer über den Frame = alter STACK)
  2214. ;    BLOCK           : ein BLOCK-Frame
  2215. ;                      belegt 3 STACK-Einträge und 2+*jmpbuf-size* SP-Einträge
  2216. ;                      Muß bei Unwind explizit aufgelöst werden
  2217. ;    (TAGBODY n)     : ein TAGBODY-Frame, der n Tags aufhebt
  2218. ;                      belegt 3+n STACK-Einträge und 1+*jmpbuf-size* SP-Einträge
  2219. ;                      Muß bei Unwind explizit aufgelöst werden
  2220. ;    MVCALLP         : Vorbereitung für MVCALL
  2221. ;                      belegt 1 STACK-Eintrag und 1 SP-Eintrag (Pointer über
  2222. ;                      FRAME = STACK)
  2223. ;    MVCALL          : viele Lisp-Objekte
  2224. ;                      belegt ? STACK-Einträge und 1 SP-Eintrag (Pointer über
  2225. ;                      Frame = alter STACK)
  2226.  
  2227. (defvar *stackz*)    ; der aktuelle Stackzustand
  2228.  
  2229. ; (stackz-fun stackz) extrahiert aus einem Stackzustand die Funktion, in der
  2230. ; gerade gearbeitet wird.
  2231. #|
  2232. (defun stackz-fun (stackz)
  2233.   (loop (when (atom stackz) (return)) (setq stackz (cdr stackz)))
  2234.   stackz
  2235. )
  2236. |#
  2237. ; äquivalent, aber schneller:
  2238. (defun stackz-fun (stackz)
  2239.   (if (atom stackz) stackz (cdr (last stackz)))
  2240. )
  2241.  
  2242. ; (in-same-function-p stackz1 stackz2) stellt fest, ob in beiden Stackzuständen
  2243. ; in derselben Funktion gearbeitet wird.
  2244. (defun in-same-function-p (stackz1 stackz2)
  2245.   (eq (stackz-fun stackz1) (stackz-fun stackz2))
  2246. )
  2247.  
  2248. ; (zugriff-in-stack stackz1 stackz2)
  2249. ; Für den Zugriff auf lokale Variablen im Stack:
  2250. ; ergibt zu zwei Stackzuständen stackz1 und stackz2, die beide innerhalb
  2251. ; derselben Funktion liegen und wo stackz1 "tiefer" ist als stackz2:
  2252. ; 2 Werte: NIL und n, falls (stackz2) = (STACK+4*n) von stackz1 aus,
  2253. ;          k und n, falls (stackz2) = ((SP+4*k)+4*n) von stackz1 aus.
  2254. ; (Falls stackz2 mit BLOCK oder TAGBODY beginnt, ist immer der Zugriff auf die
  2255. ;  consvar eines Block- bzw. Tagbody-Frames gemeint.)
  2256. (defun zugriff-in-stack (stackz1 stackz2 &aux (k nil) (n 0) (kd 0))
  2257.   (loop ; beim Durchlaufen der Stacks nach oben:
  2258.     ; momentanes STACK ist STACK+4*n (bei k=NIL) bzw. (SP+4*k)+4*n,
  2259.     ; momentanes SP ist SP+4*kd (bei k=NIL) bzw. SP+4*(k+kd).
  2260.     (when (eq stackz1 stackz2) (return))
  2261.     (when (atom stackz1) (compiler-error 'zugriff-in-stack "STACKZ-END"))
  2262.     (let ((item (car stackz1)))
  2263.       (cond ((integerp item) (setq n (+ n item)))
  2264.             ((consp item)
  2265.              (case (first item)
  2266.                (BIND    (setq n (+ n (+ 1 (* 2 (second item))))))
  2267.                (TAGBODY (setq kd (+ kd (+ 1 *jmpbuf-size*))
  2268.                               n (+ n (+ 3 (second item)))
  2269.                )        )
  2270.                (t (compiler-error 'zugriff-in-stack "STACKZ-LISTITEM"))
  2271.             ))
  2272.             (t
  2273.              (case item
  2274.                (PROGV          (setq k (if k (+ k kd) kd) kd 1 n 0))
  2275.                (CATCH          (setq kd (+ kd (+ 2 *jmpbuf-size*)) n (+ n 3)))
  2276.                (UNWIND-PROTECT (setq kd (+ kd (+ 2 *jmpbuf-size*)) n (+ n 2)))
  2277.                (CLEANUP        (setq k (if k (+ k kd) kd) kd 3 n 0))
  2278.                (BLOCK          (setq kd (+ kd (+ 2 *jmpbuf-size*)) n (+ n 3)))
  2279.                (MVCALLP        (setq kd (+ kd 1) n (+ n 1)))
  2280.                (MVCALL         (setq k (if k (+ k kd) kd) kd 1 n 0))
  2281.                (t (compiler-error 'zugriff-in-stack "STACKZ-ITEM"))
  2282.     ) )     ))
  2283.     (setq stackz1 (cdr stackz1))
  2284.   )
  2285.   (when (and (consp stackz2) ; beim Zugriff auf BLOCK- bzw. TAGBODY-consvar:
  2286.              (or (eq (car stackz2) 'BLOCK)
  2287.                  (and (consp (car stackz2)) (eq (first (car stackz2)) 'TAGBODY))
  2288.         )    )
  2289.     (setq n (+ n 2)) ; consvar liegt genau 2 Einträge höher als Frameanfang
  2290.   )
  2291.   (values k n)
  2292. )
  2293.  
  2294. ; (expand-UNWIND stackz1 stackz2 for-value)
  2295. ; liefert ein zu (UNWIND stackz1 stackz2 for-value) äquivalentes Codestück,
  2296. ; bestehend aus
  2297. ; (SKIP n), (SKIPI k n), (SKIPSP k), (VALUES0), (UNWIND-PROTECT-CLEANUP),
  2298. ; (UNBIND1), (BLOCK-CLOSE), (TAGBODY-CLOSE).
  2299. ; Es muß - ausgehend von stackz1 - den Stack so bereinigen, daß danach der
  2300. ; Stackzustand stackz2 vorliegt. Bei for-value=NIL können die Werte dabei
  2301. ; weggeworfen werden.
  2302. (defun expand-UNWIND (stackz1 stackz2 for-value
  2303.                       &aux (k nil) (n 0) (kd 0) (codelist nil))
  2304.   (flet ((here () ; bis hierher erst einmal die Stacks hochsetzen
  2305.            (if k
  2306.              (progn
  2307.                (push `(SKIPI ,k ,n) codelist)
  2308.                (when (<= kd 0) (compiler-error 'expand-UNWIND "SP-depth"))
  2309.                (when (> kd 1) (push `(SKIPSP ,(- kd 1)) codelist))
  2310.              )
  2311.              (progn
  2312.                (when (> n 0) (push `(SKIP ,n) codelist))
  2313.                (when (> kd 0) (push `(SKIPSP ,kd) codelist))
  2314.            ) )
  2315.            (setq k nil n 0 kd 0)
  2316.         ))
  2317.     (loop ; beim Durchlaufen der Stacks nach oben:
  2318.       ; momentanes STACK ist STACK+4*n (bei k=NIL) bzw. (SP+4*k)+4*n,
  2319.       ; momentanes SP ist SP+4*kd (bei k=NIL) bzw. SP+4*(k+kd).
  2320.       (when (eq stackz1 stackz2) (here) (return))
  2321.       (when (atom stackz1) (compiler-error 'expand-UNWIND "STACKZ-END"))
  2322.       (let ((item (car stackz1)))
  2323.         (cond ((integerp item) (setq n (+ n item)))
  2324.               ((consp item)
  2325.                (case (first item)
  2326.                  (BIND    (here) (push '(UNBIND1) codelist))
  2327.                  (TAGBODY (here) (push '(TAGBODY-CLOSE) codelist))
  2328.                  (t (compiler-error 'expand-UNWIND "STACKZ-LISTITEM"))
  2329.               ))
  2330.               (t
  2331.                (case item
  2332.                  (PROGV (here) (push '(UNBIND1) codelist) (setq kd 1))
  2333.                  (CATCH (setq kd (+ kd (+ 2 *jmpbuf-size*)) n (+ n 3)))
  2334.                  (UNWIND-PROTECT
  2335.                    (here)
  2336.                    (unless for-value
  2337.                       ; bei for-value=NIL wird beim ersten auftretenden
  2338.                       ; UNWIND-PROTECT-Frame ein '(VALUES0) eingefügt.
  2339.                      (setq for-value t)
  2340.                      (push '(VALUES0) codelist)
  2341.                    )
  2342.                    (push '(UNWIND-PROTECT-CLEANUP) codelist)
  2343.                  )
  2344.                  (CLEANUP (setq k (if k (+ k kd) kd) kd 3 n 0))
  2345.                  (BLOCK (here) (push '(BLOCK-CLOSE) codelist))
  2346.                  (MVCALLP (setq kd (+ kd 1) n (+ n 1)))
  2347.                  (MVCALL (setq k (if k (+ k kd) kd) kd 1 n 0))
  2348.                  (t (compiler-error 'expand-UNWIND "STACKZ-ITEM"))
  2349.       ) )     ))
  2350.       (setq stackz1 (cdr stackz1))
  2351.     )
  2352.     (nreverse codelist)
  2353. ) )
  2354.  
  2355.  
  2356.  
  2357. ;        F U N C T I O N - E N V I R O N M E N T - V E R W A L T U N G
  2358.  
  2359. ; mitgegeben vom Interpreter: %fenv%
  2360.  
  2361. ; Interpreter-Funktions-Environment hat die Gestalt
  2362. ; %fenv% = NIL oder #(f1 def1 ... fn defn NEXT-ENV), NEXT-ENV von derselben
  2363. ; Gestalt.
  2364. ; Damit ist eine Abbildung fi --> defi realisiert.
  2365. ; defi = (SYSTEM::MACRO . expander)  bedeutet einen lokalen Macro.
  2366. ; defi = Closure                     bedeutet, daß defi die lokale
  2367. ;                                    Funktionsdefinition von fi ist
  2368. ; defi = NIL                         bedeutet, daß eine lokale Funktions-
  2369. ;                                    definition noch hineinkommt (vgl. LABELS)
  2370.  
  2371. ; neu konstruiert:
  2372. (defvar *fenv*)
  2373. ; enthält die neuen lexikalischen Funktionsbindungen.
  2374. ; *fenv* hat dieselbe Gestalt wie %fenv% und endet mit %fenv%:
  2375. ; #(f1 def1 ... fn defn NEXT-ENV), was eine Abbildung fi --> defi
  2376. ; realisiert.
  2377. ; defi = (SYSTEM::MACRO expander)  bedeutet einen lokalen Makro.
  2378. ; defi = (fdescr . var)            bedeutet, daß die lokale Funktionsdefinition
  2379. ;           von fi zur Laufzeit in der lexikalischen Variablen var steckt.
  2380. ;           fnode ist der zu fi gehörige fnode, anfangs noch NIL.
  2381. ; defi = (fdescr . const)          bedeutet, daß die lokale Funktionsdefinition
  2382. ;           von fi autonom ist und in der Konstanten const steckt.
  2383. ;           fnode ist der zu fi gehörige fnode, anfangs noch NIL.
  2384. ; Dabei ist fdescr ein Cons (fnode . lambdadescr),
  2385. ;           fnode der zu fi gehörige fnode oder NIL,
  2386. ;           lambdadescr = (LABELS . Liste der Werte von analyze-lambdalist)
  2387. ;           oder lambdadescr = (GENERIC . Signature) oder NIL.
  2388.  
  2389. ; Suche die lokale Funktionsdefinition des Symbols f in fenv :
  2390. ; Ergebnis ist:
  2391. ; SYSTEM::MACRO, expander           bei einem lokalen Macro,
  2392. ; GLOBAL, Vektor, Index             wenn defi = (svref Vektor Index)
  2393. ;                                   (also in %fenv% gefunden)
  2394. ; LOCAL, def, fdescr                wenn defi = def eine Variable oder Konstante
  2395. ;                                   (also in *fenv* ohne %fenv% gefunden)
  2396. ; NIL                               falls nicht lokal definiert.
  2397. (defun fenv-search (f &optional (fenv *fenv*))
  2398.   (loop
  2399.     (when (null fenv) (return-from fenv-search 'NIL))
  2400.     (unless (simple-vector-p fenv) (compiler-error 'fenv-search))
  2401.     (do ((l (1- (length fenv)))
  2402.          (i 0 (+ i 2)))
  2403.         ((= i l) (setq fenv (svref fenv i)))
  2404.       (if (equal f (svref fenv i))
  2405.         (let ((def (svref fenv (1+ i))))
  2406.           (return-from fenv-search
  2407.             (if (consp def)
  2408.               (if (eq (car def) 'SYSTEM::MACRO)
  2409.                 (values 'SYSTEM::MACRO (cdr def))
  2410.                 (values 'LOCAL (cdr def) (car def))
  2411.               )
  2412.               (values 'GLOBAL fenv (1+ i))
  2413.   ) ) ) ) ) )
  2414. )
  2415. ; Stellt fest, ob ein Funktionsname im Function-Environment fenv nicht
  2416. ; definiert ist und daher auf die globale Funktion verweist.
  2417. (defun global-in-fenv-p (s fenv)
  2418.   (eq (fenv-search s fenv) 'NIL)
  2419. )
  2420.  
  2421. ; Mit einem Vektor aus
  2422. ; - einem solchen Variablen-Environment (verkettete Vektoren, mit
  2423. ;   defi = #<SYMBOL-MACRO expansion> für Symbol-Macro-Definitionen),
  2424. ; - einem solchen Funktions-Environment (verkettete Vektoren, mit
  2425. ;   defi = (SYSTEM::MACRO . expander) für Macro-Definitionen zu fi)
  2426. ; arbeiten die Funktionen
  2427. ; MACROEXPAND-1, MACROEXPAND, PARSE-BODY:
  2428. #|
  2429. (MACROEXPAND-1 form env) expandiert die gegebene Form im Macroexpansions-
  2430. Environment env und liefert die 1 mal expandierte Form und T
  2431. (oder form und NIL, falls nicht expandierbar).
  2432.  
  2433. (MACROEXPAND form env) expandiert die gegebene Form im Macroexpansions-
  2434. Environment env und liefert die sooft wie möglich expandierte Form und T
  2435. (oder form und NIL, falls nicht expandierbar).
  2436.  
  2437. (PARSE-BODY body docstring-allowed env) analysiert den body und spaltet von
  2438. ihm die Deklarationen und den Docstring (falls erlaubt und vorhanden) ab.
  2439. 3 Werte: der übrige body-rest, eine Liste der vorgekommenen declspecs,
  2440. der Docstring (oder NIL).
  2441. |#
  2442.  
  2443.  
  2444. ;           B L O C K - E N V I R O N M E N T - V E R W A L T U N G
  2445.  
  2446. ; mitgegeben vom Interpreter: %benv%
  2447.  
  2448. ; Interpreter-Block-Environment hat die Gestalt
  2449. ; %benv% = ((name1 . status1) ... (namen . statusn))
  2450. ; wobei namei ein Symbol und statusi der Status dieses lexikalisch umfassenden
  2451. ; Blocks ist: #<DISABLED> falls der Block bereits verlassen wurde, sonst ein
  2452. ; Pointer in den Stack auf den zugehörigen Block-Frame.
  2453.  
  2454. ; neu konstruiert:
  2455. (defvar *benv*)
  2456.  
  2457. ; *benv* hat die Gestalt
  2458. ; ((name1 . block1) ... (namen . blockn) . %benv%)
  2459. ; wobei blocki der Descriptor des Blocks mit Namen namei ist:
  2460. (defstruct (block (:copier nil))
  2461.   fnode                 ; Funktion, in der dieser Block definiert ist, ein FNODE
  2462.   label                 ; label, an dem dieser Block zu Ende ist
  2463.   stackz                ; Stackzustand nach dem Aufbau des Block-Frames
  2464.   consvar               ; Variable, die im Stack im Block-Frame liegt und den
  2465.                         ; Block-Cons enthält (dessen CDR beim Verlassen des
  2466.                         ; Blockes auf #<DISABLED> gesetzt wird)
  2467.   used-far              ; Flag, gibt an, ob dieser Block aus einer anderen
  2468.                         ; Funktion heraus mit RETURN-FROM verlassen wird.
  2469.   for-value             ; gibt an, ob das gesamte Block-Konstrukt Werte
  2470.                         ; zurückliefern soll.
  2471. )
  2472. #+CLISP (remprop 'block 'sys::defstruct-description)
  2473.  
  2474. ; Sucht nach einem Block mit dem Namen name und liefert:
  2475. ; NIL                          falls nicht gefunden,
  2476. ; Block-Descriptor             falls in *benv* gefunden,
  2477. ; Block-Cons (name . status)   falls in %benv% gefunden.
  2478. (defun benv-search (name &optional (benv *benv*))
  2479.   (loop
  2480.     (when (atom benv) (return nil))
  2481.     (when (eq (caar benv) name)
  2482.       (if (block-p (cdar benv))
  2483.         (return (cdar benv))
  2484.         (return (car benv))
  2485.     ) )
  2486.     (setq benv (cdr benv))
  2487. ) )
  2488.  
  2489.  
  2490. ;         T A G B O D Y - E N V I R O N M E N T - V E R W A L T U N G
  2491.  
  2492. ; mitgegeben vom Interpreter: %genv%
  2493.  
  2494. ; Interpreter-Tagbody-Environment hat die Gestalt
  2495. ; %genv% = ((Tagvektor1 . status1) ... (Tagvektorn . statusn))
  2496. ; wobei Tagvektori ein simple-vector ist, der die anspringbaren Tags enthält,
  2497. ; statusi der Status dieses lexikalisch umfassenden Tagbodys
  2498. ; ist: #<DISABLED> falls der Tagbody bereits verlassen wurde, sonst ein
  2499. ; Pointer in den Stack auf den zugehörigen Tagbody-Frame.
  2500.  
  2501. ; neu konstruiert:
  2502. (defvar *genv*)
  2503.  
  2504. ; *genv* hat die Gestalt
  2505. ; ((Tagvektor1 . tagbody1) ... (Tagvektorn . tagbodyn) . %genv%)
  2506. ; wobei tagbodyi der Descriptor des Tagbodys i ist:
  2507. (defstruct (tagbody (:copier nil))
  2508.   fnode               ; Funktion, in der dieser Tagbody definiert ist, ein FNODE
  2509.   labellist           ; Liste der Labels, parallel zum Tagvektor
  2510.   stackz              ; Stackzustand nach dem Aufbau des Tagbody-Frames
  2511.   consvar             ; Variable, die im Stack im Tagbody-Frame liegt und den
  2512.                       ; Tagbody-Cons enthält (dessen CDR beim Verlassen des
  2513.                       ; Tagbodys auf #<DISABLED> gesetzt wird)
  2514.   used-far            ; Vektor mit Fill-Pointer, enthält all die Tags, die
  2515.                       ; aus einer anderen Funktion heraus mit GO angesprungen
  2516.                       ; werden.
  2517. )
  2518. #+CLISP (remprop 'tagbody 'sys::defstruct-description)
  2519.  
  2520. ; Sucht nach einem Tag mit dem Namen name und liefert:
  2521. ; NIL                                         falls nicht gefunden,
  2522. ; Tagbody-Descriptor, Index                   falls in *genv* gefunden,
  2523. ; Tagbody-Cons (Tagvektor . status), Index    falls in %genv% gefunden.
  2524. (defun genv-search (name &optional (genv *genv*))
  2525.   (loop
  2526.     (when (atom genv) (return nil))
  2527.     (do* ((v (caar genv))
  2528.           (l (length v))
  2529.           (i 0 (1+ i)))
  2530.          ((= i l))
  2531.       (when (eql (svref v i) name)
  2532.         (return-from genv-search
  2533.           (values (if (tagbody-p (cdar genv)) (cdar genv) (car genv)) i)
  2534.     ) ) )
  2535.     (setq genv (cdr genv))
  2536. ) )
  2537.  
  2538.  
  2539. ;       V A R I A B L E N - E N V I R O N M E N T - V E R W A L T U N G
  2540.  
  2541. ; mitgegeben vom Interpreter: %venv%
  2542.  
  2543. ; Interpreter-Variablen-Environment hat die Gestalt
  2544. ; %venv% = NIL oder #(v1 val1 ... vn valn NEXT-ENV), NEXT-ENV von derselben
  2545. ; Gestalt.
  2546. (defconstant specdecl
  2547.   #+CLISP (eval
  2548.             '(let ((*evalhook*
  2549.                      #'(lambda (form env) (declare (ignore form))
  2550.                          (svref (svref env 0) 1)
  2551.                          ; Der Evalhook-Mechanismus übergibt das Environment.
  2552.                          ; (svref...0) davon ist das Variablen-Environment,
  2553.                          ; (svref...1) davon ist von der *evalhook*-Bindung
  2554.                          ; der assoziierte "Wert" #<SPECIAL REFERENCE>.
  2555.                   ))   )
  2556.                0
  2557.           )  )
  2558.   #-CLISP (cons nil nil)
  2559. )
  2560. ; stellt fest, ob das Symbol var eine Special-Variable darstellt
  2561. #+CLISP
  2562. (defun proclaimed-special-p (var)
  2563.   (or (sys::special-variable-p var)
  2564.       (not (null (member var *known-special-vars* :test #'eq)))
  2565. ) )
  2566. #-CLISP
  2567. (defun proclaimed-special-p (var)
  2568.   (or
  2569.     (eq var '*evalhook*)
  2570.     (eq var '*applyhook*)
  2571.     (eq var '*macroexpand-hook*)
  2572.     (let ((obj (cons nil nil)))
  2573.       (eval
  2574.         `(let ((,var ',obj))
  2575.            (and (boundp ',var) (eq (symbol-value ',var) ',obj))
  2576.     ) )  )
  2577.     (not (null (member var *known-special-vars* :test #'eq)))
  2578. ) )
  2579.  
  2580. ; neu konstruiert:
  2581. (defvar *venv*)                  ; Variablen-Environment, Feinstruktur
  2582. (defvar *venvc*)                 ; Variablen-Environment, Grobstruktur
  2583.  
  2584. ; *venv* hat dieselbe Gestalt wie %venv% und endet mit %venv%:
  2585. ; #(v1 var1 ... vn varn NEXT_ENV), wo vari Variablen-Konstrukte oder
  2586. ; Symbolmacros oder Interpreter-Werte sind und NEXT-ENV von derselben Gestalt.
  2587.  
  2588. ; *venvc* simuliert das Laufzeit-Variablen-Environment zur Laufzeit, soweit
  2589. ; es sich um Closure-Variablen handelt.
  2590. ; *venvc* hat die Gestalt
  2591. ; (item1 ... itemn)
  2592. ; jedes item ist
  2593. ;   NIL :            ein LET/LET*/MULTIPLE-VALUE-BIND/Funktionseintritt/
  2594. ;                    FLET/LABELS, der keine Closure aufmacht
  2595. ;   fnode :          eine neue Funktion
  2596. ;   ((var1 ... vark) . stackz) : durch ein LET/LET*/MULTIPLE-VALUE-BIND/
  2597. ;                    Funktionseintritt/FLET/LABELS kommen die Variablen
  2598. ;                    Var1, ..., Vark in eine Closure.
  2599. ;                    Diese Closure liegt im Stack; angegeben der
  2600. ;                    Stackzustand, an der sie erreichbar ist.
  2601.  
  2602. ; Eine Variable wird beschrieben dadurch, daß sie entweder special ist oder
  2603. ; - falls lexikalisch - der Stackaufbau nach dem Anlegen der Variablen im Stack
  2604. ; bzw. der Ort in der Closure festliegt.
  2605. (defstruct (var (:copier nil))
  2606.   (name nil :read-only t)     ; Symbol
  2607.   (specialp nil :read-only t) ; special deklariert (oder lexikalisch gebunden) ?
  2608.   constantp                   ; Konstante ?
  2609.   constant                    ; wenn Konstante: Wert und Herkunft der Konstanten
  2610.   usedp                       ; falls lexikalisch:
  2611.                               ;   wurde die Variable jemals abgefragt ?
  2612.                               ;   (Eine durch NIL oder T beendete Liste der
  2613.                               ;    Referenzen auf die Variable)
  2614.   really-usedp                ; falls lexikalisch:
  2615.                               ;   wurde die Variable jemals wirklich
  2616.                               ;   (um den Wert zu wissen) abgefragt ?
  2617.   (modified-list '())         ; falls lexikalisch: zu jedem SET auf die Variable
  2618.                               ;   ein Cons (value-anode . set-anode)
  2619.   (replaceable-list '())      ; falls lexikalisch:
  2620.                               ;   zu jeder movable-Variablen, die während ihrer
  2621.                               ;   gesamten Existenz denselben Wert wie diese
  2622.                               ;   hat und deswegen ersetzbar ist, jeweils eine
  2623.                               ;   Liste (var init-anode . bind-anode)
  2624.   closurep                    ; falls lexikalisch:
  2625.                               ;   NIL falls im Stack, T falls in der Closure
  2626.   (stackz nil :read-only t)   ; falls lexikalisch:
  2627.                               ;   Stackzustand nach dem Anlegen der Variablen
  2628.                               ;   (falls Variable im Stack: ihr Ort im Stack)
  2629.   (venvc nil :read-only t)    ; falls lexikalisch und in der Closure:
  2630.                               ;   das *venvc*, in dessen erstem Item diese
  2631.                               ;   Variable vorkommt.
  2632. )
  2633. #+CLISP (remprop 'var 'sys::defstruct-description)
  2634.  
  2635. ; (venv-search v) sucht in *venv* nach einer Variablen mit dem Symbol v.
  2636. ; Ergebnis ist:
  2637. ; NIL                   falls nicht gefunden
  2638. ; SPECIAL               falls als Special-deklarierte Variable gefunden
  2639. ; LOCAL, vector, index  falls interpretativ lexikalisch gebunden, Wert im Vektor
  2640. ; T, var                falls lexikalisch gebunden, im Stack oder in der Closure
  2641. (defun venv-search (v &optional (venv *venv*))
  2642.   (when (or (constantp v) (proclaimed-special-p v))
  2643.     (return-from venv-search 'SPECIAL)
  2644.   )
  2645.   (loop
  2646.     (cond ((null venv) (return-from venv-search 'NIL))
  2647.           ((simple-vector-p venv)
  2648.            (do ((l (1- (length venv)))
  2649.                 (i 0 (+ i 2)))
  2650.                ((= i l) (setq venv (svref venv i)))
  2651.              (if (eq v (svref venv i))
  2652.                (let ((val (svref venv (1+ i))))
  2653.                  (return-from venv-search
  2654.                    (if (and (var-p val) #| (eq (var-name val) v) |# )
  2655.                      (if (var-specialp val) 'SPECIAL (values T val))
  2656.                      (if (eq val specdecl) 'SPECIAL (values 'LOCAL venv (1+ i)))
  2657.           )) ) ) ) )
  2658.           (t (compiler-error 'venv-search))
  2659.   ) )
  2660. )
  2661.  
  2662. ; (venv-search-macro v) sucht in *venv* nach einer Variablen mit dem Symbol v.
  2663. ; Ergebnis ist ein Symbol-Macro-Objekt genau dann, wenn v ein Symbol-Macro
  2664. ; darstellt.
  2665. (defun venv-search-macro (v &optional (venv *venv*))
  2666.   (multiple-value-bind (a b c) (venv-search v venv)
  2667.     (case a
  2668.       ((NIL) (and (boundp v) (symbol-value v)))
  2669.       ((LOCAL) (svref b c))
  2670.       (t nil)
  2671. ) ) )
  2672.  
  2673. ; (push-*venv* var1 ... varn) erweitert *venv* um var1, ..., varn,
  2674. ; sozusagen wie durch  (dolist (v (list var1 ... varn)) (push v *venv*)).
  2675. (defun push-*venv* (&rest varlist)
  2676.   (when varlist
  2677.     (let ((l (list *venv*)))
  2678.       (dolist (var varlist) (setq l (list* (var-name var) var l)))
  2679.       (setq *venv* (apply #'vector l))
  2680. ) ) )
  2681.  
  2682. ; (zugriff-in-closure var venvc stackz)
  2683. ; liefert zu einer Closure-Variablen var, wie man auf sie zugreifen kann
  2684. ; (von einem Ort aus, an der Stack und das Closure-Environment durch stackz und
  2685. ;  venvc beschrieben werden):
  2686. ; 3 Werte k, n, m; die Variable sitzt in (svref ... 1+m) von
  2687. ;     nil, n, m  : (STACK+4*n)
  2688. ;     k, nil, m  : (svref ... 0)^k VenvConst
  2689. ;     k, n,   m  : ((SP+4*k)+4*n)
  2690. (defun zugriff-in-closure (var venvc stackz &aux (k nil) n)
  2691.   ; Grobschleife, stellt die Closure-Tiefe k ab VenvConst fest:
  2692.   (loop
  2693.     (when (eq venvc (var-venvc var)) (return))
  2694.     (let ((item (car venvc)))
  2695.       (if (null k)
  2696.         (when (not (listp item)) (setq k 0)) ; Zählanfang, (not (listp item)) == (fnode-p item)
  2697.         (when (consp item) (incf k)) ; zählen
  2698.     ) )
  2699.     (setq venvc (cdr venvc))
  2700.   )
  2701.   (if k
  2702.     (setq n nil)
  2703.     (multiple-value-setq (k n) (zugriff-in-stack stackz (cdr (first venvc))))
  2704.   )
  2705.   (let ((m (do ((L (car (first venvc)) (cdr L))
  2706.                 (i 0 (1+ i)))
  2707.                ((eq (car L) var) i)
  2708.        ))  )
  2709.     (values k n m)
  2710. ) )
  2711.  
  2712.  
  2713. ;             K O N S T A N T E N - V E R W A L T U N G
  2714.  
  2715. ; Eine Konstante ist eine Box mit dem Wert der Konstanten:
  2716. (defstruct (const (:copier nil))
  2717.   value               ; Wert der Konstanten
  2718.   (form nil)          ; falls /= NIL: Symbol, das konstant ist,
  2719.     ; bzw. allgemeiner: Form, die bei Auswertung value ergibt.
  2720. )
  2721. #+CLISP (remprop 'const 'sys::defstruct-description)
  2722. ; Im 2. Pass werden auch Variablen mit constantp=T als Konstanten behandelt.
  2723.  
  2724.  
  2725. ;           D E K L A R A T I O N E N - V E R W A L T U N G
  2726.  
  2727. (defparameter *declaration-types*
  2728.   '(special ; Bindungen
  2729.     type ftype function ; Typen
  2730.     inline notinline ; Funktionen-Compilation
  2731.     ignore optimize ; Compiler-Hinweise
  2732.     declaration ; Zusatzdeklarationen
  2733.     ; Typen nach Tabelle 4-1 :
  2734.     array atom bignum bit bit-vector character common compiled-function
  2735.     complex cons double-float fixnum float function hash-table integer keyword
  2736.     list long-float nil null number package pathname random-state ratio rational
  2737.     readtable sequence short-float simple-array simple-bit-vector simple-string
  2738.     simple-vector single-float standard-char stream string string-char symbol t
  2739.     vector
  2740.     ; zusätzliche Deklarationen:
  2741.     compile ; Anweisung, daß die Form bzw. Funktion zu compilieren ist
  2742.     sys::source ; der Source-Lambdabody (unexpandiert) innerhalb eines Lambdabody
  2743.     sys::in-defun ; zeigt an, zu welcher globalen Funktion der Code gehört
  2744.     sys::ignorable ; markiert Variablen als vielleicht ignorierbar
  2745.                    ; (NB: Gensym-Variablen sind immer automatisch ignorable.)
  2746. )  )
  2747.  
  2748. ; mitgegeben vom Interpreter: %denv%
  2749.  
  2750. ; neu konstruiert:
  2751. (defvar *denv*)
  2752. ; *denv* hat dieselbe Gestalt wie %denv% und endet mit %denv%.
  2753. ; *denv* hat die Gestalt (item1 ... itemn), wo jedes item die Bauart
  2754. ; (declaration-type argument ...) hat.
  2755. ; Sonderbehandlung von
  2756. ;   SPECIAL : wird weggelassen, stattdessen in *venv* notiert.
  2757. ;   IGNORE, SYSTEM::IGNORABLE : wird weggelassen, stattdessen bei der
  2758. ;                               verarbeitenden Form selber verarbeitet.
  2759. ; Zusätzliche Deklaration (INLINING symbol) gegen rekursives Inlining.
  2760.  
  2761. ; (process-declarations declspeclist) pusht die Deklarationen (wie sie von
  2762. ; PARSE-BODY kommen) auf *denv* und liefert:
  2763. ; eine Liste der Special-deklarierten Symbole,
  2764. ; eine Liste der Ignore-deklarierten Symbole,
  2765. ; eine Liste der Ignorable-deklarierten Symbole.
  2766. (defun process-declarations (declspeclist &aux (specials nil) (ignores nil) (ignorables nil))
  2767.   (setq declspeclist (nreverse declspeclist))
  2768.   (dolist (declspec declspeclist)
  2769.     (if (or (atom declspec) (cdr (last declspec)))
  2770.       (c-warn #+DEUTSCH "Falsche Deklarationen-Syntax: ~S~%Wird ignoriert."
  2771.               #+ENGLISH "Bad declaration syntax: ~S~%Will be ignored."
  2772.               declspec
  2773.       )
  2774.       (let ((declspectype (car declspec)))
  2775.         (if (and (symbolp declspectype)
  2776.                  (or (member declspectype *declaration-types* :test #'eq)
  2777.                      (do ((L *denv* (cdr L)))
  2778.                          ((null L) nil)
  2779.                        (if (and (eq (first (car L)) 'DECLARATION)
  2780.                                 (member declspectype (rest (car L)) :test #'eq)
  2781.                            )
  2782.                          (return t)
  2783.                      ) )
  2784.                      (and *compiling-from-file*
  2785.                        (member declspectype *user-declaration-types* :test #'eq)
  2786.             )    )   )
  2787.           (cond ((eq declspectype 'SPECIAL)
  2788.                  (dolist (x (cdr declspec))
  2789.                    (if (symbolp x)
  2790.                      (push x specials)
  2791.                      (c-warn #+DEUTSCH "Nur Symbole können SPECIAL-deklariert werden, nicht ~S."
  2792.                              #+ENGLISH "Non-symbol ~S may not be declared SPECIAL."
  2793.                              x
  2794.                 )) ) )
  2795.                 ((eq declspectype 'IGNORE)
  2796.                  (dolist (x (cdr declspec))
  2797.                    (if (symbolp x)
  2798.                      (push x ignores)
  2799.                      (c-warn #+DEUTSCH "Nur Symbole können IGNORE-deklariert werden, nicht ~S."
  2800.                              #+ENGLISH "Non-symbol ~S may not be declared IGNORE."
  2801.                              x
  2802.                 )) ) )
  2803.                 ((eq declspectype 'SYS::IGNORABLE)
  2804.                  (dolist (x (cdr declspec))
  2805.                    (if (symbolp x)
  2806.                      (push x ignorables)
  2807.                      (c-warn #+DEUTSCH "Nur Symbole können IGNORABLE-deklariert werden, nicht ~S."
  2808.                              #+ENGLISH "Non-symbol ~S may not be declared IGNORABLE."
  2809.                              x
  2810.                 )) ) )
  2811.                 (t (push declspec *denv*))
  2812.           )
  2813.           (c-warn #+DEUTSCH "Unbekannte Deklaration ~S.~%Die ganze Deklaration ~S wird ignoriert."
  2814.                   #+ENGLISH "Unknown declaration ~S.~%The whole declaration will be ignored."
  2815.                   declspectype declspec
  2816.   ) ) ) ) )
  2817.   (values specials ignores ignorables)
  2818. )
  2819.  
  2820. ; (declared-notinline fun denv) stellt fest, ob fun - ein Symbol, das eine
  2821. ; globale Funktion, die nicht durch eine lokale Funktionsdefinition verdeckt
  2822. ; ist, benennt - in denv als NOTINLINE deklariert ist.
  2823. ; Was ist mit lokalen Funktionen ??
  2824. (defun declared-notinline (fun &optional (denv *denv*))
  2825.   (when (member `(INLINING ,fun) *denv* :test #'equal)
  2826.     (return-from declared-notinline t) ; keine Funktion rekursiv inline expandieren!
  2827.   )
  2828.   (loop
  2829.     (when (atom denv)
  2830.       (when *compiling-from-file*
  2831.         (when (member fun *notinline-functions* :test #'equal) (return t))
  2832.         (when (member fun *inline-functions* :test #'equal) (return nil))
  2833.       )
  2834.       (return (eq (get (get-funname-symbol fun) 'inlinable) 'notinline))
  2835.     )
  2836.     (let ((declspec (car denv)))
  2837.       (when (and (eq (car declspec) 'INLINE) (member fun (cdr declspec) :test #'equal))
  2838.         (return nil)
  2839.       )
  2840.       (when (and (eq (car declspec) 'NOTINLINE) (member fun (cdr declspec) :test #'equal))
  2841.         (return t)
  2842.     ) )
  2843.     (setq denv (cdr denv))
  2844. ) )
  2845.  
  2846.  
  2847. ;             F U N K T I O N E N - V E R W A L T U N G
  2848.  
  2849. ; Ein FNODE enthält die nötige Information für eine Funktion:
  2850. (defstruct (fnode (:copier nil))
  2851.   name            ; Name, ein Symbol oder (SETF symbol)
  2852.   code            ; Code dieser Funktion (zuerst nichts, dann ein ANODE,
  2853.                   ; dann eine Closure)
  2854.   ; Ab hier Beschreibungen für die kommende Closure:
  2855.   venvconst       ; Flag, ob das Venv dieser Funktion explizit beim Aufbau
  2856.                   ; mitgegeben werden muß (oder immer NIL ist)
  2857.   venvc           ; Aussehen des Venv, das dieser Funktion beim Aufbau
  2858.                   ; mitgegeben werden muß (wenn überhaupt)
  2859.   Blocks-Offset   ; Anzahl der Konstanten bis hierher
  2860.   (Blocks nil)    ; Liste der Block-Konstrukte, die dieser Funktion beim Aufbau
  2861.                   ; mitgegeben werden müssen
  2862.   Tagbodys-Offset ; Anzahl der Konstanten bis hierher
  2863.   (Tagbodys nil)  ; Liste der Tagbody-Konstrukte, die dieser Funktion beim
  2864.                   ; Aufbau mitgegeben werden müssen
  2865.   Keyword-Offset  ; Anzahl der lokalen Konstanten bis hierher
  2866.                   ; = Anfangsoffset der Keywords in FUNC
  2867.                   ; (also =0 genau dann, wenn die Funktion autonom ist)
  2868.   (req-anz 0)     ; Anzahl der required parameter
  2869.   (opt-anz 0)     ; Anzahl der optionalen Parameter
  2870.   (rest-flag nil) ; Flag, ob &REST - Parameter angegeben.
  2871.   (keyword-flag nil) ; Flag, ob &KEY - Parameter angegeben.
  2872.   (keywords nil)  ; Liste der Keyword-Konstanten (in der richtigen Reihenfolge)
  2873.   allow-other-keys-flag ; &ALLOW-OTHER-KEYS-Flag
  2874.   Consts-Offset   ; Anzahl der lokalen Konstanten bis hierher
  2875.   (consts nil)    ; Liste der sonstigen Konstanten dieser Funktion
  2876.                   ; Diese Liste wird erst im 2. Pass aufgebaut.
  2877.   (consts-forms nil) ; Liste der evtl. Formen, die diese Konstanten ergeben
  2878.   enclosing       ; lexikalisch nächste darüberliegende Funktion (oder NIL)
  2879.   gf-p            ; Flag, ob eine generische Funktion produziert wird
  2880.                   ; (impliziert Blocks-Offset = Tagbodys-Offset = Keyword-Offset = 0 oder 1)
  2881. )
  2882. #+CLISP (remprop 'fnode 'sys::defstruct-description)
  2883.  
  2884. ; die aktuelle Funktion, ein FNODE:
  2885. (defvar *func*)
  2886. ; das Label am Beginn des Codes der aktuellen Funktion:
  2887. (defvar *func-start-label*)
  2888.  
  2889. ; Anzahl der bisher in der aktuellen Funktion aufgetretenen anonymen
  2890. ; Funktionen (Lambda-Ausdrücke):
  2891. (defvar *anonymous-count*)
  2892.  
  2893. ; *no-code* = T besagt, daß kein Code produziert werden soll:
  2894. (defvar *no-code*)
  2895. ; Dies verhindert, daß Variablen unnötigerweise in die Closure gesteckt oder
  2896. ; Optimierungen unnötigerweise unterlassen werden.
  2897.  
  2898.  
  2899. ;                 F O R M E N - V E R W A L T U N G
  2900.  
  2901. ; Bei jeder Rekursion werden folgende Variablen dynamisch gebunden:
  2902. (defvar *form*)      ; die aktuelle Form
  2903. (defvar *for-value*) ; ob und welche Werte der Form von Belang sind:
  2904.                      ; NIL : Werte sind irrelevant
  2905.                      ; ONE : nur der erste Wert ist relevant
  2906.                      ; ALL : alle Werte sind relevant
  2907.  
  2908. ; Ein ANODE ist die Codierung der Information, die beim Compilieren einer Form
  2909. ; gebraucht wird.
  2910. (defstruct (anode
  2911.             (:constructor mk-anode (#+COMPILER-DEBUG source
  2912.                                     type
  2913.                                     #+COMPILER-DEBUG sub-anodes
  2914.                                     seclass
  2915.                                     code
  2916.                                     #+COMPILER-DEBUG stackz
  2917.             )                      )
  2918.             (:copier nil)
  2919.            )
  2920.   #+COMPILER-DEBUG
  2921.   source              ; die zu dieser Form gehörige Source, meist eine Form
  2922.                       ; (nur zu Debugzwecken erforderlich)
  2923.   type                ; Typ des ANODE (CALL, PRIMOP, VAR, LET, SETQ, ...)
  2924.   #+COMPILER-DEBUG
  2925.   sub-anodes          ; alle ANODEs der Unterformen
  2926.   seclass             ; Seiteneffekt-Klassifikation
  2927.   code                ; erzeuger LAP-Code, eine Liste aus LAP-Anweisungen
  2928.                       ; und ANODEs
  2929.   #+COMPILER-DEBUG
  2930.   stackz              ; Zustand der Stacks beim Eintritt in den zugehörigen
  2931.                       ; LAP-Code
  2932. )
  2933. #+CLISP (remprop 'anode 'sys::defstruct-description)
  2934. ; (make-anode ...) ist dasselbe wie mk-anode, nur daß dabei die Argumente
  2935. ; mit Keywords markiert werden und wegen #+COMPILER-DEBUG unnötige
  2936. ; Komponenten trotzdem dastehen dürfen.
  2937. (eval-when (compile eval)
  2938.   (defmacro make-anode (&key
  2939.                         (source `*form*)
  2940.                         type
  2941.                         (sub-anodes `'())
  2942.                         seclass
  2943.                         code
  2944.                         (stackz `*stackz*)
  2945.                        )
  2946.     `(mk-anode #+COMPILER-DEBUG ,source
  2947.                ,type
  2948.                #+COMPILER-DEBUG ,sub-anodes
  2949.                ,seclass
  2950.                ,code
  2951.                #+COMPILER-DEBUG ,stackz
  2952.      )
  2953. ) )
  2954.  
  2955. #|
  2956. ; Eine Seiteneffekt-Klasse (SECLASS) ist ein Indikator:
  2957. ; NIL : dieses ANODE produziert keine Seiteneffekte,
  2958. ;       sein Wert ist nicht von Seiteneffekten beeinflußbar.
  2959. ; VAL : dieses ANODE produziert keine Seiteneffekte,
  2960. ;       sein Wert ist aber von Seiteneffekten beeinflußbar.
  2961. ; T   : dieses ANODE kann Seiteneffekte produzieren.
  2962. ; Somit:
  2963. ;   Falls der Wert uninteressant ist, kann ein ANODE mit SECLASS = NIL/VAL
  2964. ;   weggelassen werden.
  2965. ;   In der Reihenfolge der Auswertung dürfen vertauscht werden ANODEs mit
  2966. ;   SECLASS     NIL-NIL, NIL-VAL, NIL-T, VAL-VAL.
  2967.  
  2968. ; (seclass-or class1 ... classk) bestimmt die Gesamtklasse der Ausführung
  2969. ; aller Klassen.
  2970. (defun seclass-or (&rest args)
  2971.   (cond ((member 'T args :test #'eq) 'T)
  2972.         ((member 'VAL args :test #'eq) 'VAL)
  2973.         (t 'NIL)
  2974. ) )
  2975. ; Dito, mit nur 2 Argumenten
  2976. (defun seclass-or-2 (seclass1 seclass2)
  2977.   (or (eq seclass1 'T) seclass2 seclass1)
  2978. )
  2979. ; Damit die Liste der sub-anodes nicht gebildet werden muß, aber dennoch
  2980. ; der zu dieser Liste gehörige Seiteneffektklasse berechnet werden kann:
  2981. (eval-when (compile eval)
  2982.   (defmacro anodes-seclass-or (&rest anodeforms)
  2983.     (reduce #'(lambda (form1 form2) `(SECLASS-OR-2 ,form1 ,form2))
  2984.             (mapcar #'(lambda (anodeform) `(ANODE-SECLASS ,anodeform))
  2985.                     anodeforms
  2986.   ) )       )
  2987.   (define-modify-macro seclass-or-f (anode) seclass-or-anode)
  2988.   (defmacro seclass-or-anode (seclass anode)
  2989.     `(SECLASS-OR-2 ,seclass (ANODE-SECLASS ,anode))
  2990.   )
  2991. )
  2992. (defun anodelist-seclass-or (anodelist)
  2993.   (apply #'seclass-or (mapcar #'anode-seclass anodelist))
  2994. )
  2995.  
  2996. ; Stellt fest, ob zwei Anodes in der Reihenfolge ihrer Auswertung vertauscht
  2997. ; werden können - vorausgesetzt, die Stackzustände lassen das zu.
  2998. (defun anodes-commute (anode1 anode2)
  2999.   (let ((seclass1 (anode-seclass anode1))
  3000.         (seclass2 (anode-seclass anode2)))
  3001.     (or (eq seclass1 'NIL) (eq seclass2 'NIL)
  3002.         (and (eq seclass1 'VAL) (eq seclass2 'VAL))
  3003. ) ) )
  3004. |#
  3005.  
  3006. ; Eine Seiteneffekt-Klasse (SECLASS) ist ein Indikator (uses . modifies):
  3007. ; uses = NIL : dieses Anode ist nicht von Seiteneffekten beeinflußbar,
  3008. ;        Liste : dieses Anode ist vom Wert der Variablen in der Liste abhängig,
  3009. ;        T : dieses Anode ist möglicherweise von jedem Seiteneffekt beeinflußbar.
  3010. ; modifies = NIL : dieses Anode produziert keine Seiteneffekte
  3011. ;            Liste : ... produziert Seiteneffekte nur auf die Werte der
  3012. ;                    Variablen in der Liste
  3013. ;            T : ... produziert Seiteneffekte unbekannten Ausmaßes.
  3014. ; (Variablen sind hier VAR-Structures für lexikalische und Symbole für
  3015. ; dynamische Variablen.)
  3016. ; Somit:
  3017. ;   Falls der Wert uninteressant ist, kann ein ANODE mit SECLASS-modifies=NIL
  3018. ;   weggelassen werden.
  3019. ;   In der Reihenfolge der Auswertung dürfen vertauscht werden ANODEs mit
  3020. ;   SECLASS, deren uses- und modifies-Teil über Kreuz disjunkt sind.
  3021.  
  3022. ; (seclass-or class1 ... classk) bestimmt die Gesamtklasse der Ausführung
  3023. ; aller Klassen.
  3024. (defun seclass-or (&rest args)
  3025.   (if (null args) '(NIL . NIL) (reduce #'seclass-or-2 args))
  3026. )
  3027. ; Dito, mit nur 2 Argumenten
  3028. (defun seclass-or-2 (seclass1 seclass2)
  3029.   (cons (if (or (eq (car seclass1) 'T) (eq (car seclass2) 'T))
  3030.           'T
  3031.           (union (car seclass1) (car seclass2))
  3032.         )
  3033.         (if (or (eq (cdr seclass1) 'T) (eq (cdr seclass2) 'T))
  3034.           'T
  3035.           (union (cdr seclass1) (cdr seclass2))
  3036. ) )     )
  3037.  
  3038. ; Damit die Liste der sub-anodes nicht gebildet werden muß, aber dennoch
  3039. ; der zu dieser Liste gehörige Seiteneffektklasse berechnet werden kann:
  3040. (eval-when (compile eval)
  3041.   (defmacro anodes-seclass-or (&rest anodeforms)
  3042.     (reduce #'(lambda (form1 form2) `(SECLASS-OR-2 ,form1 ,form2))
  3043.             (mapcar #'(lambda (anodeform) `(ANODE-SECLASS ,anodeform))
  3044.                     anodeforms
  3045.   ) )       )
  3046.   (define-modify-macro seclass-or-f (anode) seclass-or-anode)
  3047.   (defmacro seclass-or-anode (seclass anode)
  3048.     `(SECLASS-OR-2 ,seclass (ANODE-SECLASS ,anode))
  3049.   )
  3050. )
  3051. (defun anodelist-seclass-or (anodelist)
  3052.   (apply #'seclass-or (mapcar #'anode-seclass anodelist))
  3053. )
  3054.  
  3055. ; Seiteneffekte auf weiter innen gebundene lexikalische Variablen zählen
  3056. ; nicht und werden deshalb eliminiert:
  3057. (defun seclass-without (seclass varlist)
  3058.   (flet ((bound (var) (member var varlist))) ; testet, ob var gebunden wird
  3059.     ; (Dynamische Variablen werden nicht eliminiert; sie sind in varlist
  3060.     ; als VAR-Structures und in seclass als Symbole enthalten.)
  3061.     (cons (if (eq (car seclass) 'T) 'T (remove-if #'bound (car seclass)))
  3062.           (if (eq (cdr seclass) 'T) 'T (remove-if #'bound (cdr seclass)))
  3063. ) ) )
  3064.  
  3065. ; Stellt fest, ob zwei Anodes in der Reihenfolge ihrer Auswertung vertauscht
  3066. ; werden können - vorausgesetzt, die Stackzustände lassen das zu.
  3067. (defun anodes-commute (anode1 anode2)
  3068.   (seclasses-commute (anode-seclass anode1) (anode-seclass anode2))
  3069. )
  3070. (defun seclasses-commute (seclass1 seclass2)
  3071.   (flet ((disjoint-p (uses modifies)
  3072.            (or (null uses) (null modifies)
  3073.                (and (not (eq uses 'T)) (not (eq modifies 'T))
  3074.                     (null (intersection uses modifies))
  3075.         )) )   )
  3076.     (and (disjoint-p (car seclass1) (cdr seclass2))
  3077.          (disjoint-p (car seclass2) (cdr seclass1))
  3078. ) ) )
  3079.  
  3080.  
  3081. ;            H I L F S F U N K T I O N E N
  3082.  
  3083. ; Zerlegt einen Funktionsnamen in Package und String.
  3084. (defun get-funname-string+pack (funname)
  3085.   (if (atom funname)
  3086.     (values (symbol-name funname) (symbol-package funname))
  3087.     (values (concatenate 'string "(" (symbol-name (first funname)) " "
  3088.                                      (symbol-name (second funname)) ")"
  3089.             )
  3090.             (symbol-package (second funname))
  3091. ) ) )
  3092.  
  3093. ; Liefert einen Funktionsnamen, der sich aus der Package und dem Printname eines
  3094. ; gegebenen Funktionsnamen, einem Bindestrich und einem Suffix zusammensetzt.
  3095. (defun symbol-suffix (funname suffix)
  3096.   (if (and (symbolp funname) (null (symbol-package funname))
  3097.            (function-name-p suffix)
  3098.       )
  3099.     suffix
  3100.     (multiple-value-bind (name pack) (get-funname-string+pack funname)
  3101.       ; suffix in einen String umwandeln:
  3102.       (cond ((symbolp suffix) (setq suffix (symbol-name suffix)))
  3103.             ((not (stringp suffix))
  3104.              (setq suffix (write-to-string suffix :escape nil :base 10 :radix nil))
  3105.       )     )
  3106.       ; neues Symbol bilden:
  3107.       (let ((new-name (concatenate 'string name "-" suffix)))
  3108.         (if pack (intern new-name pack) (make-symbol new-name))
  3109. ) ) ) )
  3110.  
  3111. ; (C-COMMENT controlstring . args)
  3112. ; gibt eine Zusatzinformation des Compilers aus (mittels FORMAT).
  3113. (defun c-comment (cstring &rest args)
  3114.   (let ((dest (if *compile-verbose* *c-error-output* *c-listing-output*)))
  3115.     (when dest (apply #'format dest cstring args))
  3116. ) )
  3117.  
  3118. (defvar *warning-count*)
  3119. ; (C-WARN controlstring . args)
  3120. ; gibt eine Compiler-Warnung aus (mittels FORMAT).
  3121. (defun c-warn (cstring &rest args)
  3122.   (setq cstring
  3123.     (concatenate 'string #+DEUTSCH "~%WARNUNG~@[ in Funktion ~S~] :~%"
  3124.                          #+ENGLISH "~%WARNING~@[ in function ~S~] :~%"
  3125.                          cstring
  3126.   ) )
  3127.   (incf *warning-count*)
  3128.   (let ((dest (if *compile-warnings* *c-error-output* *c-listing-output*)))
  3129.     (when dest
  3130.       (apply #'format dest cstring
  3131.              (and (boundp '*func*) (fnode-p *func*) (fnode-name *func*))
  3132.              args
  3133. ) ) ) )
  3134.  
  3135. (defvar *error-count*)
  3136. ; (C-ERROR controlstring . args)
  3137. ; gibt einen Compiler-Error aus (mittels FORMAT) und beendet das laufende C-FORM.
  3138. (defun c-error (cstring &rest args)
  3139.   (setq cstring
  3140.     (concatenate 'string #+DEUTSCH "~%ERROR~@[ in Funktion ~S~] :~%"
  3141.                          #+ENGLISH "~%ERROR~@[ in function ~S~] :~%"
  3142.                          cstring
  3143.   ) )
  3144.   (incf *error-count*)
  3145.   (let ((in-function
  3146.           (and (boundp '*func*) (fnode-p *func*) (fnode-name *func*))
  3147.        ))
  3148.     (when in-function
  3149.       (when *compiling-from-file* (pushnew in-function *functions-with-errors*))
  3150.     )
  3151.     (apply #'format *c-error-output* cstring in-function args)
  3152.   )
  3153.   (throw 'c-error
  3154.     (make-anode :source NIL
  3155.                 :type 'ERROR
  3156.                 :sub-anodes '()
  3157.                 :seclass '(NIL . NIL)
  3158.                 :code '((NIL))
  3159. ) ) )
  3160.  
  3161. ; (c-eval-when-compile form) führt eine Form zur Compile-Zeit aus.
  3162. (defun c-eval-when-compile (form)
  3163.   (when (and *compiling-from-file* *liboutput-stream*)
  3164.     ; Form auf den Liboutput-Stream schreiben:
  3165.     (terpri *liboutput-stream*)
  3166.     (write form :stream *liboutput-stream* :pretty t
  3167.                 :closure t :circle t :array t :gensym t
  3168.                 :escape t :level nil :length nil :radix t
  3169.   ) )
  3170.   ; Form evaluieren:
  3171.   (eval form)
  3172. )
  3173.  
  3174. ; (c-constantp form) stellt fest, ob form im Compiler als Konstante gehandhabt
  3175. ; wird.
  3176. (defun c-constantp (form)
  3177.   (if (atom form)
  3178.     (or (numberp form) (characterp form) (stringp form) (bit-vector-p form)
  3179.         (and (symbolp form)
  3180.              (cond ((keywordp form) t)
  3181.                    ((eq (symbol-package form) *lisp-package*)
  3182.                     (constantp form)
  3183.                    )
  3184.                    (t (not (null (assoc form *constant-special-vars*))))
  3185.     )   )    )
  3186.     (and (eq (first form) 'QUOTE) (consp (cdr form)) (null (cddr form)))
  3187. ) )
  3188.  
  3189. ; (c-constant-value form) liefert den Wert einer Konstanten
  3190. (defun c-constant-value (form)
  3191.   (if (atom form)
  3192.     (cond ((numberp form) form)
  3193.           ((characterp form) form)
  3194.           ((stringp form) form)
  3195.           ((bit-vector-p form) form)
  3196.           ((symbolp form)
  3197.            (cond ((keywordp form) form)
  3198.                  ((eq (symbol-package form) *lisp-package*)
  3199.                   (symbol-value form)
  3200.                  )
  3201.                  (t (cdr (assoc form *constant-special-vars*)))
  3202.     )     ))
  3203.     (second form)
  3204. ) )
  3205.  
  3206. ; (anode-constantp anode) stellt fest, ob der Anode einen konstanten Wert
  3207. ; liefert.
  3208. (defun anode-constantp (anode)
  3209.   ; Anode liefert konstanten Wert jedenfalls dann, wenn sein Code
  3210.   ; (nach TRAVERSE-ANODE) genau aus ((CONST ...)) bestehen würde.
  3211.   (let ((code (anode-code anode)))
  3212.     (and (consp code) (null (cdr code)) ; Liste der Länge 1
  3213.          (let ((item (car code)))
  3214.             (cond ((consp item) (eq (first item) 'CONST))
  3215.                   ((anode-p item) (anode-constantp item))
  3216. ) ) )    )  )
  3217.  
  3218. ; (anode-constant-value anode) liefert den Wert eines konstanten Anode.
  3219. (defun anode-constant (anode)
  3220.   (let ((item (car (anode-code anode))))
  3221.     (cond ((consp item) (second item))
  3222.           (t #|(anode-p item)|# (anode-constant item))
  3223. ) ) )
  3224. (defun anode-constant-value (anode)
  3225.   (const-value (anode-constant anode))
  3226. )
  3227.  
  3228. ; (new-const value) liefert eine Konstante in *func* mit dem Wert value
  3229. ; im 1. Pass
  3230. (defun new-const (value)
  3231.   (make-const :value value)
  3232. )
  3233.  
  3234. ; (make-label for-value) liefert ein neues Label. for-value (NIL/ONE/ALL)
  3235. ; gibt an, welche der Werte nach dem Label gebraucht werden.
  3236. (defun make-label (for-value)
  3237.   (let ((label (gensym)))
  3238.     (setf (symbol-value label) '()) ; Referenzliste für 2. Pass := leer
  3239.     (setf (get label 'for-value) for-value)
  3240.     label
  3241. ) )
  3242.  
  3243. ; liefert eine Special-Variable
  3244. (defun make-special-var (symbol)
  3245.   (make-var :name symbol :specialp t
  3246.             :constantp (c-constantp symbol)
  3247.             :constant (if (c-constantp symbol)
  3248.                         (make-const :value (c-constant-value symbol)
  3249.                                     :form symbol
  3250. ) )                   ) )
  3251.  
  3252.  
  3253. ;                     E R S T E R   P A S S
  3254.  
  3255. ; (test-list L) stellt fest, ob L eine echte Liste ist, die mit NIL endet
  3256. ; und mindestens l1, höchstens aber l2 Elemente hat. Sonst Error.
  3257. (defun test-list (L &optional (l1 0) (l2 nil))
  3258.   (unless (and (listp L) (null (cdr (last L))))
  3259.     (c-error #+DEUTSCH "Dotted list im Code: ~S"
  3260.              #+ENGLISH "Code contains dotted list ~S"
  3261.              L
  3262.   ) )
  3263.   (unless (>= (length L) l1)
  3264.     (c-error #+DEUTSCH "Form zu kurz (zu wenig Argumente): ~S"
  3265.              #+ENGLISH "Form too short, too few arguments: ~S"
  3266.              L
  3267.   ) )
  3268.   (when l2
  3269.     (unless (<= (length L) l2)
  3270.       (c-error #+DEUTSCH "Form zu lang (zu viele Argumente): ~S"
  3271.                #+ENGLISH "Form too long, too many arguments: ~S"
  3272.                L
  3273.   ) ) )
  3274. )
  3275.  
  3276. ; c-form-table enthält zu allen Funktionen/Specialforms/Macros, die speziell
  3277. ; behandelt werden müssen, die Behandlungsfunktion (ohne Argumente aufzurufen).
  3278. (defconstant c-form-table
  3279.   (let ((hashtable (make-hash-table :test #'eq)))
  3280.     (mapc
  3281.       #'(lambda (acons) (setf (gethash (car acons) hashtable) (cdr acons)))
  3282.       `(; Special forms:
  3283.           (QUOTE . c-QUOTE)
  3284.           (PROGN . c-PROGN)
  3285.           (LET . ,#'(lambda () (c-LET/LET* nil)))
  3286.           (LET* . ,#'(lambda () (c-LET/LET* t)))
  3287.           (IF . c-IF)
  3288.           (SETQ . c-SETQ)
  3289.           (BLOCK . c-BLOCK)
  3290.           (RETURN-FROM . c-RETURN-FROM)
  3291.           (TAGBODY . c-TAGBODY)
  3292.           (GO . c-GO)
  3293.           (FUNCTION . c-FUNCTION)
  3294.           (MULTIPLE-VALUE-BIND . c-MULTIPLE-VALUE-BIND)
  3295.           (MULTIPLE-VALUE-SETQ . c-MULTIPLE-VALUE-SETQ)
  3296.           (AND . c-AND)
  3297.           (OR . c-OR)
  3298.           (WHEN . c-WHEN)
  3299.           (UNLESS . c-UNLESS)
  3300.           (COND . c-COND)
  3301.           (PSETQ . c-PSETQ)
  3302.           (MULTIPLE-VALUE-CALL . c-MULTIPLE-VALUE-CALL)
  3303.           (PROG1 . c-PROG1)
  3304.           (PROG2 . c-PROG2)
  3305.           (THE . c-THE)
  3306.           (CATCH . c-CATCH)
  3307.           (THROW . c-THROW)
  3308.           (UNWIND-PROTECT . c-UNWIND-PROTECT)
  3309.           (PROGV . c-PROGV)
  3310.           (MULTIPLE-VALUE-LIST . c-MULTIPLE-VALUE-LIST)
  3311.           (MULTIPLE-VALUE-PROG1 . c-MULTIPLE-VALUE-PROG1)
  3312.           (FLET . c-FLET)
  3313.           (LABELS . c-LABELS)
  3314.           (MACROLET . c-MACROLET)
  3315.           (SYMBOL-MACROLET . c-SYMBOL-MACROLET)
  3316.           (COMPILER-LET . c-COMPILER-LET)
  3317.           (EVAL-WHEN . c-EVAL-WHEN)
  3318.           (DECLARE . c-DECLARE)
  3319.           (LOAD-TIME-VALUE . c-LOAD-TIME-VALUE)
  3320.           (LOCALLY . c-LOCALLY)
  3321.         ; Macros:
  3322.           (CASE . c-CASE)
  3323.           (%GENERIC-FUNCTION-LAMBDA . c-%GENERIC-FUNCTION-LAMBDA)
  3324.           (%OPTIMIZE-FUNCTION-LAMBDA . c-%OPTIMIZE-FUNCTION-LAMBDA)
  3325.           (CLOS:GENERIC-FLET . c-GENERIC-FLET)
  3326.           (CLOS:GENERIC-LABELS . c-GENERIC-LABELS)
  3327.         ; Inline-compilierte Funktionen:
  3328.           (FUNCALL . c-FUNCALL)
  3329.           (SYS::%FUNCALL . c-FUNCALL)
  3330.           (APPLY . c-APPLY)
  3331.           (+ . c-PLUS)
  3332.           (- . c-MINUS)
  3333.           (SYS::SVSTORE . c-SVSTORE)
  3334.           (EQ . c-EQ)
  3335.           (EQL . c-EQL)
  3336.           (EQUAL . c-EQUAL)
  3337.           (MAPCAR . c-MAPCAR)
  3338.           (MAPLIST . c-MAPLIST)
  3339.           (MAPC . c-MAPC)
  3340.           (MAPL . c-MAPL)
  3341.           (MAPCAN . c-MAPCAN)
  3342.           (MAPCON . c-MAPCON)
  3343.           (MAPCAP . c-MAPCAP)
  3344.           (MAPLAP . c-MAPLAP)
  3345.           (TYPEP . c-TYPEP)
  3346.     )  )
  3347.     hashtable
  3348. ) )
  3349. ; Diese Tabelle muß alle Special-Forms enthalten:
  3350. (do-all-symbols (sym)
  3351.   (when (and (special-form-p sym) (not (gethash sym c-form-table)))
  3352.     (compiler-error 'c-form-table)
  3353. ) )
  3354.  
  3355. ; compiliert eine Form.
  3356. ; Dabei ergibt sich kein Code, falls keine Werte gebraucht werden und die Form
  3357. ; keine Seiteneffekte produziert.
  3358. (defun c-form (*form* &optional (*for-value* *for-value*))
  3359.  (let
  3360.   ((anode
  3361.     (catch 'c-error
  3362.       (if (atom *form*)
  3363.         (cond ((symbolp *form*)
  3364.                (let ((h (venv-search-macro *form* *venv*)))
  3365.                  (if (symbol-macro-p h) ; Symbol-Macro ?
  3366.                    (c-form (sys::%record-ref h 0)) ; -> expandieren
  3367.                    (c-VAR *form*)
  3368.               )) )
  3369.               ((or (numberp *form*) (characterp *form*) (stringp *form*)
  3370.                    (bit-vector-p *form*)
  3371.                )
  3372.                (c-CONST)
  3373.               )
  3374.               (t (c-error #+DEUTSCH "Das ist keine gültige Form: ~S"
  3375.                           #+ENGLISH "Invalid form: ~S"
  3376.                           *form*
  3377.         )     )  )
  3378.         (let ((fun (first *form*)))
  3379.           (if (function-name-p fun)
  3380.             (multiple-value-bind (a b c) (fenv-search fun)
  3381.               (declare (ignore b))
  3382.               (if (null a)
  3383.                 ; nicht lokal definiert
  3384.                 (let ((handler (gethash fun c-form-table)))
  3385.                   (if handler ; Behandlungsfunktion gefunden?
  3386.                     (funcall handler) ; ja -> aufrufen
  3387.                     ; nein -> jedenfalls keine Special-Form (die sind ja
  3388.                     ; alle in der Tabelle).
  3389.                     (if (and (symbolp fun) (macro-function fun)) ; globaler Macro ?
  3390.                       (c-form (macroexpand-1 *form* (vector *venv* *fenv*))) ; -> expandieren
  3391.                       ; globale Funktion
  3392.                       (if (and (equal fun (fnode-name *func*))
  3393.                                (not (declared-notinline fun))
  3394.                                (member `(SYS::IN-DEFUN ,fun) *denv* :test #'equal)
  3395.                           )
  3396.                         ; rekursiver Aufruf der aktuellen globalen Funktion
  3397.                         (c-LOCAL-FUNCTION-CALL fun (cons *func* nil) (cdr *form*))
  3398.                         ; normaler Aufruf globaler Funktion
  3399.                         (c-GLOBAL-FUNCTION-CALL fun)
  3400.                 ) ) ) )
  3401.                 (case a
  3402.                   (SYSTEM::MACRO ; lokaler Macro
  3403.                     (c-form (macroexpand-1 *form* (vector *venv* *fenv*))) ; -> expandieren
  3404.                   )
  3405.                   (GLOBAL ; Funktion im Interpreter-Environment %fenv% gefunden
  3406.                     ; (c-form `(SYS::%FUNCALL (FUNCTION ,fun) ,@(cdr *form*)))
  3407.                     (c-FUNCALL-NOTINLINE `(FUNCTION ,fun) (cdr *form*))
  3408.                   )
  3409.                   (LOCAL ; lokale Funktion (in *fenv* gefunden)
  3410.                     ; (c-form `(SYS::%FUNCALL (FUNCTION ,fun) ,@(cdr *form*)))
  3411.                     (c-LOCAL-FUNCTION-CALL fun c (cdr *form*))
  3412.                   )
  3413.                   (t (compiler-error 'c-form))
  3414.             ) ) )
  3415.             (if (and (consp fun) (eq (car fun) 'LAMBDA))
  3416.               (c-form `(SYS::%FUNCALL (FUNCTION ,fun) ,@(cdr *form*)))
  3417.               #| nicht: (c-LAMBDA-FUNCTION-CALL fun (cdr *form*)) |#
  3418.               (c-error #+DEUTSCH "Das ist nicht der Name einer Funktion: ~S"
  3419.                        #+ENGLISH "Not the name of a function: ~S"
  3420.                        fun
  3421.     ) ) ) ) ) )
  3422.   ))
  3423.   #+COMPILER-DEBUG (setf (anode-source anode) *form*)
  3424.   ; Falls keine Werte gebraucht werden und keine Seiteneffekte produziert
  3425.   ; werden, kann der dazugehörige Code ganz gestrichen werden:
  3426.   (when (and (null *for-value*) (null (cdr (anode-seclass anode))))
  3427.     (setf (anode-code anode) '())
  3428.     (setf (anode-seclass anode) '(NIL . NIL))
  3429.   )
  3430.   anode
  3431. ))
  3432.  
  3433. ; compiliere NIL (eine Art Notausgang)
  3434. (defun c-NIL ()
  3435.   (make-anode :type 'NIL
  3436.               :sub-anodes '()
  3437.               :seclass '(NIL . NIL)
  3438.               :code '((NIL)) )
  3439. )
  3440.  
  3441. ; Konstante als Form:
  3442. (defun c-CONST ()
  3443.   (make-anode :type 'const
  3444.               :sub-anodes '()
  3445.               :seclass '(NIL . NIL)
  3446.               :code `((CONST ,(new-const *form*)))
  3447. ) )
  3448.  
  3449. ; Variable als Form:
  3450. (defun c-VAR (symbol)
  3451.   ; Suche die Variable in *venv* :
  3452.   (multiple-value-bind (a b c) (venv-search symbol)
  3453.     (when (eq a 'NIL)
  3454.       (c-warn #+DEUTSCH "~S ist weder deklariert noch gebunden,~@
  3455.                          behandle es als SPECIAL-deklarierte Variable."
  3456.               #+ENGLISH "~S is neither declared nor bound,~@
  3457.                          it will be treated as if it were declared SPECIAL."
  3458.               symbol
  3459.       )
  3460.       (when *compiling-from-file*
  3461.         (pushnew symbol *unknown-free-vars* :test #'eq)
  3462.       )
  3463.       (setq a 'SPECIAL)
  3464.     )
  3465.     (case a
  3466.       (SPECIAL ; Special-Variable
  3467.         (let ((var (make-special-var symbol)))
  3468.           (make-anode
  3469.             :type 'VAR
  3470.             :sub-anodes '()
  3471.             :seclass (cons
  3472.                        (if (and *for-value* (not (var-constantp var))) (list symbol) 'NIL)
  3473.                        'NIL
  3474.                      )
  3475.             :code (if *for-value*
  3476.                     (if (var-constantp var)
  3477.                       `((CONST ,(make-const
  3478.                                   :value (c-constant-value symbol)
  3479.                                   :form (if (keywordp symbol) nil symbol)
  3480.                        ))       )
  3481.                       `((GETVALUE ,symbol))
  3482.                     )
  3483.                     '()
  3484.       ) ) )       )
  3485.       (LOCAL ; interpretativ lexikalisch
  3486.         (make-anode
  3487.           :type 'VAR
  3488.           :sub-anodes '()
  3489.           :seclass (cons (if *for-value* 'T 'NIL) 'NIL)
  3490.           :code (if *for-value*
  3491.                   `((CONST ,(new-const b)) ; Vektor
  3492.                     (PUSH)
  3493.                     (CONST ,(new-const c)) ; Index
  3494.                     (SVREF)
  3495.                    )
  3496.                   '()
  3497.       ) )       )
  3498.       ((T) ; lexikalisch in Stack oder Closure
  3499.         (let* ((var b)
  3500.                (get-anode
  3501.                  (make-anode
  3502.                    :type 'VAR
  3503.                    :sub-anodes '()
  3504.                    :seclass (cons (if *for-value* (list var) 'NIL) 'NIL)
  3505.                    :code (if *for-value*
  3506.                            `((GET ,var ,*venvc* ,*stackz*))
  3507.                            '()
  3508.               )) )       )
  3509.           (push get-anode (var-usedp var))
  3510.           (when (and *for-value* (not *no-code*))
  3511.             (setf (var-really-usedp var) t)
  3512.             (unless (eq (stackz-fun (var-stackz var)) *func*)
  3513.               (setf (var-closurep var) t)
  3514.             )
  3515.             (when (var-closurep var)
  3516.               ; aktiviere Venvconst in allen dazwischenliegenden Funktionen
  3517.               (do ((venvc *venvc* (cdr venvc)))
  3518.                   ((null venvc) (compiler-error 'c-VAR "INVISIBLE"))
  3519.                 (when (eq venvc (var-venvc var)) (return))
  3520.                 (when (fnode-p (car venvc))
  3521.                   (setf (fnode-Venvconst (car venvc)) t)
  3522.           ) ) ) )
  3523.           get-anode
  3524.       ) )
  3525.       (t (compiler-error 'c-VAR 'venv-search))
  3526. ) ) )
  3527.  
  3528. ; Variablenzuweisung:
  3529. (defun c-VARSET (symbol value-anode)
  3530.   ; Suche die Variable in *venv* :
  3531.   (multiple-value-bind (a b c) (venv-search symbol)
  3532.     (when (eq a 'NIL)
  3533.       (c-warn #+DEUTSCH "~S ist weder deklariert noch gebunden,~@
  3534.                          behandle es als SPECIAL-deklarierte Variable."
  3535.               #+ENGLISH "~S is neither declared nor bound,~@
  3536.                          it will be treated as if it were declared SPECIAL."
  3537.               symbol
  3538.       )
  3539.       (setq a 'SPECIAL)
  3540.     )
  3541.     (case a
  3542.       (SPECIAL ; Special-Variable
  3543.         (let ((var (make-special-var symbol)))
  3544.           (make-anode :type 'VARSET
  3545.                       :sub-anodes '()
  3546.                       :seclass (cons
  3547.                                  'NIL
  3548.                                  (if (var-constantp var) 'NIL (list symbol))
  3549.                                )
  3550.                       :code (if (var-constantp var)
  3551.                               (progn
  3552.                                 (c-warn #+DEUTSCH "Der Konstante ~S kann nicht zugewiesen werden.~@
  3553.                                                    Die Zuweisung wird ignoriert."
  3554.                                         #+ENGLISH "The constant ~S may not be assigned to.~@
  3555.                                                    The assignment will be ignored."
  3556.                                         symbol
  3557.                                 )
  3558.                                 '((VALUES1))
  3559.                               )
  3560.                               `((SETVALUE , symbol))
  3561.       ) ) )                 )
  3562.       (LOCAL ; interpretativ lexikalisch
  3563.         (make-anode :type 'VARSET
  3564.                     :sub-anodes '()
  3565.                     :seclass (cons 'NIL 'T)
  3566.                     :code `((PUSH)
  3567.                             (CONST ,(new-const b)) ; Vektor
  3568.                             (PUSH)
  3569.                             (CONST ,(new-const c)) ; Index
  3570.                             (SVSET)
  3571.       ) )                  )
  3572.       ((T) ; lexikalisch in Stack oder Closure
  3573.         (let* ((var b)
  3574.                (set-anode
  3575.                  (make-anode :type 'VARSET
  3576.                              :sub-anodes '()
  3577.                              :seclass (cons 'NIL (list var))
  3578.                              :code `((SET ,var ,*venvc* ,*stackz*))
  3579.               )) )
  3580.           (unless (var-usedp var) (setf (var-usedp var) t)) ; Zuweisung "benutzt" die Variable
  3581.           (unless *no-code*
  3582.             (setf (var-constantp var) nil) ; nicht mehr konstant wegen Zuweisung
  3583.             (push (cons value-anode set-anode) (var-modified-list var))
  3584.             (unless (eq (stackz-fun (var-stackz var)) *func*)
  3585.               (setf (var-closurep var) t)
  3586.               ; aktiviere Venvconst in allen dazwischenliegenden Funktionen
  3587.               (do ((venvc *venvc* (cdr venvc)))
  3588.                   ((null venvc) (compiler-error 'c-VARSET "INVISIBLE"))
  3589.                 (when (eq venvc (var-venvc var)) (return))
  3590.                 (when (fnode-p (car venvc))
  3591.                   (setf (fnode-Venvconst (car venvc)) t)
  3592.             ) ) )
  3593.             ; Das Ersetzen einer Variablen innervar durch var ist dann
  3594.             ; nicht erlaubt, wenn während der Existenzdauer von innervar
  3595.             ; an var ein Wert zugewiesen wird.
  3596.             (setf (var-replaceable-list var)
  3597.               (delete-if #'(lambda (innervar-info) ; innervar gerade aktiv?
  3598.                              (let ((innervar (first innervar-info)))
  3599.                                (tailp (var-stackz innervar) *stackz*)
  3600.                            ) )
  3601.                          (var-replaceable-list var)
  3602.             ) )
  3603.           )
  3604.           set-anode
  3605.       ) )
  3606.       (t (compiler-error 'c-VARSET 'venv-search))
  3607. ) ) )
  3608.  
  3609. ;; Funktionsaufrufe, bei denen die Funktion ein Symbol oder (SETF symbol) ist:
  3610.  
  3611. (defun make-funname-const (name)
  3612.   (if (atom name)
  3613.     (new-const name)
  3614.     (let ((symbol (second name)))
  3615.       (make-const :value (system::get-setf-symbol symbol)
  3616.                   :form `(SYSTEM::GET-SETF-SYMBOL ',symbol)
  3617. ) ) ) )
  3618.  
  3619. ; Global function call, normal (notinline): (fun {form}*)
  3620. (defun c-NORMAL-FUNCTION-CALL (fun) ; fun ist ein Symbol oder (SETF symbol)
  3621.   (test-list *form* 1)
  3622.   (let* ((n (length (cdr *form*)))
  3623.          #+COMPILER-DEBUG (oldstackz *stackz*)
  3624.          (*stackz* *stackz*))
  3625.     (do ((formlist (cdr *form*))
  3626.          #+COMPILER-DEBUG (anodelist '())
  3627.          (codelist (list '(CALLP))))
  3628.         ((null formlist)
  3629.          (push
  3630.            `(,@(case n
  3631.                  (0 `(CALL0)) (1 `(CALL1)) (2 `(CALL2)) (t `(CALL ,n))
  3632.                )
  3633.              ,(make-funname-const fun)
  3634.             )
  3635.            codelist
  3636.          )
  3637.          (make-anode
  3638.            :type 'CALL
  3639.            :sub-anodes (nreverse anodelist)
  3640.            :seclass '(T . T)
  3641.            :code (nreverse codelist)
  3642.            :stackz oldstackz
  3643.         ))
  3644.       (let* ((formi (pop formlist))
  3645.              (anodei (c-form formi 'ONE)))
  3646.         #+COMPILER-DEBUG (push anodei anodelist)
  3647.         (push anodei codelist)
  3648.         (push '(PUSH) codelist)
  3649.         (push 1 *stackz*)
  3650. ) ) ) )
  3651.  
  3652. ; Liefert die Signatur einer Funktion aus dem fdescr
  3653. (defun fdescr-signature (fdescr)
  3654.   (if (cdr fdescr)
  3655.     (if (eq (cadr fdescr) 'LABELS)
  3656.       ; bei LABELS: aus der Lambdalisten-Information
  3657.       (multiple-value-bind (reqvar  optvar optinit optsvar  restvar
  3658.                             keyflag keyword keyvar keyinit keysvar allow-other-keys
  3659.                             auxvar auxinit)
  3660.           (values-list (cddr fdescr))
  3661.         (declare (ignore optinit optsvar keyvar keyinit keysvar auxvar auxinit))
  3662.         (values (length reqvar) (length optvar)
  3663.                 (not (eql restvar 0)) keyflag
  3664.                 keyword allow-other-keys
  3665.       ) )
  3666.       ; bei GENERIC-FLET oder GENERIC-LABELS: aus der Signatur
  3667.       (values-list (cddr fdescr))
  3668.     )
  3669.     ; bei FLET oder IN-DEFUN: aus dem fnode
  3670.     (let ((fnode (car fdescr)))
  3671.       (values (fnode-req-anz fnode) (fnode-opt-anz fnode)
  3672.               (fnode-rest-flag fnode) (fnode-keyword-flag fnode)
  3673.               (fnode-keywords fnode) (fnode-allow-other-keys-flag fnode)
  3674. ) ) ) )
  3675.  
  3676. ; (test-argument-syntax args applyargs fun req opt rest-p key-p keylist allow-p)
  3677. ; überprüft, ob die Argumentliste args (und evtl. weitere Argumente applyargs)
  3678. ; als Argumentliste zu fun (Symbol) geeignet ist, d.h. ob sie der gegebenen
  3679. ; Spezifikation, gegeben durch req,opt,rest-p,keylist,allow-p, genügt.
  3680. ; Gegebenenfalls wird eine Warnung ausgegeben.
  3681. ; Liefert:
  3682. ;   NO-KEYS           bei korrekter Syntax, ohne Keywords,
  3683. ;   STATIC-KEYS       bei korrekter Syntax mit konstanten Keywords,
  3684. ;   DYNAMIC-KEYS      bei (vermutlich) korrekter Syntax,
  3685. ;                       mit nicht-konstanten Keywords.
  3686. ;   NIL               bei fehlerhafter Syntax,
  3687. ; In den ersten beiden Fällen ist
  3688. ; falls (not applyargs):
  3689. ;   req <= (length args) <= (req+opt oder, falls rest-p oder key-p, unendlich)
  3690. ; bzw. falls applyargs:
  3691. ;   (length args) <= (req+opt oder, falls rest-p oder key-p, unendlich).
  3692. (defun test-argument-syntax (args applyargs fun req opt rest-p key-p keylist allow-p)
  3693.   (unless (and (listp args) (null (cdr (last args))))
  3694.     (c-error #+DEUTSCH "Argumentliste zu Funktion ~S ist dotted: ~S"
  3695.              #+ENGLISH "argument list to function ~S is dotted: ~S"
  3696.              fun args
  3697.   ) )
  3698.   (let ((n (length args))
  3699.         (reqopt (+ req opt)))
  3700.     (unless (and (or applyargs (<= req n)) (or rest-p key-p (<= n reqopt)))
  3701.       (c-warn #+DEUTSCH "~S mit ~S~:[~; oder mehr~] Argumenten aufgerufen, braucht aber ~
  3702.                          ~:[~:[~S bis ~S~;~S~]~;mindestens ~*~S~] Argumente."
  3703.               #+ENGLISH "~S called with ~S~:[~; or more~] arguments, but it requires ~
  3704.                          ~:[~:[from ~S to ~S~;~S~]~;at least ~*~S~] arguments."
  3705.               fun n applyargs
  3706.               (or rest-p key-p)  (eql req reqopt) req reqopt
  3707.       )
  3708.       (return-from test-argument-syntax 'NIL)
  3709.     )
  3710.     (unless key-p (return-from test-argument-syntax 'NO-KEYS))
  3711.     ; Mit Keywords.
  3712.     (when (<= n reqopt) (return-from test-argument-syntax 'STATIC-KEYS))
  3713.     (when rest-p (return-from test-argument-syntax 'DYNAMIC-KEYS))
  3714.     (setq n (- n reqopt) args (nthcdr reqopt args))
  3715.     (unless (evenp n)
  3716.       (c-warn #+DEUTSCH "Keyword-Argumente zu Funktion ~S sind nicht paarig: ~S"
  3717.               #+ENGLISH "keyword arguments to function ~S should occur pairwise: ~S"
  3718.               fun args
  3719.       )
  3720.       (return-from test-argument-syntax 'NIL)
  3721.     )
  3722.     (do ((keyargs args (cddr keyargs))
  3723.          (allow-flag allow-p)
  3724.          (wrong-key nil)
  3725.         )
  3726.         ((null keyargs)
  3727.          (if wrong-key
  3728.            (c-error #+DEUTSCH "Keyword ~S ist bei Funktion ~S nicht erlaubt.~
  3729.                                ~%Erlaubt ~:[sind nur ~{~S~#[~; und ~S~:;, ~]~}~;ist nur ~{~S~}~]."
  3730.                     #+ENGLISH "keyword ~S is not allowed for function ~S.~
  3731.                                ~%The only allowed keyword~:[s are ~{~S~#[~; and ~S~:;, ~]~}~; is ~{~S~}~]."
  3732.                     wrong-key fun (eql (length keylist) 1) keylist
  3733.            )
  3734.            'STATIC-KEYS
  3735.         ))
  3736.       (let ((key (first keyargs)))
  3737.         (unless (c-constantp key)
  3738.           (return-from test-argument-syntax 'DYNAMIC-KEYS)
  3739.         )
  3740.         (setq key (c-constant-value key))
  3741.         (unless (keywordp key)
  3742.           (c-warn #+DEUTSCH "Das Argument ~S zu Funktion ~S ist kein Keyword."
  3743.                   #+ENGLISH "argument ~S to function ~S is not a keyword"
  3744.                   (first keyargs) fun
  3745.           )
  3746.           (return-from test-argument-syntax 'DYNAMIC-KEYS)
  3747.         )
  3748.         (when (eq key ':ALLOW-OTHER-KEYS)
  3749.           (unless (c-constantp (second keyargs))
  3750.             (return-from test-argument-syntax 'DYNAMIC-KEYS)
  3751.           )
  3752.           (when (c-constant-value (second keyargs)) (setq allow-flag t))
  3753.         )
  3754.         (unless (or allow-flag (member key keylist :test #'eq))
  3755.           (setq wrong-key key)
  3756.     ) ) )
  3757. ) )
  3758.  
  3759. ; (c-DIRECT-FUNCTION-CALL args applyargs fun req opt rest-p key-p keylist
  3760. ;                         subr-flag call-code-producer)
  3761. ; compiliert die Abarbeitung der Argumente für den Direktaufruf einer
  3762. ; Funktion (d.h. ohne Argument-Check zur Laufzeit).
  3763. ; (test-argument-syntax ...) muß die Argumente bereits erfolgreich (d.h.
  3764. ; mit Ergebnis NO-KEYS oder STATIC-KEYS) überprüft haben.
  3765. ; args : Liste der Argumentformen,
  3766. ; applyargs : falls angegeben, Liste einer Form für die weiteren Argumente,
  3767. ; fun : Name der aufzurufenden Funktion (Symbol),
  3768. ; req,opt,rest-p,key-p,keylist,allow-p : Information über die Lambdaliste von fun
  3769. ; subr-flag : Flag, ob fun ein SUBR oder aber eine compilierte Closure ist,
  3770. ;             (Obacht: applyargs nur bei compilierten Closures verwenden!),
  3771. ; call-code-producer : Funktion, die den Code liefert, der am Ende anzufügen
  3772. ;                      ist und den Aufruf ausführt.
  3773. (defun c-DIRECT-FUNCTION-CALL (args applyargs fun req opt rest-p key-p keylist
  3774.                                subr-flag call-code-producer)
  3775.   (let* ((foldable nil)
  3776.          (sideeffects ; Seiteneffektklasse des Funktionsaufrufs selbst
  3777.            (if (not subr-flag)
  3778.              '(T . T) ; kein SUBR -> kann nichts aussagen
  3779.              (case fun ; fun ein SUBR
  3780.                (; Seiteneffektklasse (NIL . NIL) haben diejenigen Funktionen,
  3781.                 ; die ihre Argumente nur anschauen (Pointer, Inhalt nur bei
  3782.                 ; Zahlen oder ähnlichen unmodifizierbaren Datenstrukturen)
  3783.                 ; und auf keine globalen Variablen zugreifen.
  3784.                 ; Eine Funktion, die, zweimal mit denselben Argumenten auf-
  3785.                 ; gerufen, stets dasselbe Ergebnis liefert (im EQL-Sinne),
  3786.                 ; erlaubt Constant-Folding: Sind alle Argumente Konstanten
  3787.                 ; und der Funktionsaufruf durchführbar, so darf der Funktions-
  3788.                 ; aufruf durch das konstante Funktionsergebnis ersetzt werden.
  3789.                 (SYSTEM::%FUNTABREF
  3790.                  ARRAY-ELEMENT-TYPE ARRAY-RANK ADJUSTABLE-ARRAY-P
  3791.                  STANDARD-CHAR-P GRAPHIC-CHAR-P STRING-CHAR-P ALPHA-CHAR-P UPPER-CASE-P
  3792.                  LOWER-CASE-P BOTH-CASE-P DIGIT-CHAR-P ALPHANUMERICP CHAR= CHAR/= CHAR< CHAR>
  3793.                  CHAR<= CHAR>= CHAR-EQUAL CHAR-NOT-EQUAL CHAR-LESSP CHAR-GREATERP
  3794.                  CHAR-NOT-GREATERP CHAR-NOT-LESSP CHAR-CODE CHAR-BITS CHAR-FONT CODE-CHAR
  3795.                  MAKE-CHAR CHAR-UPCASE CHAR-DOWNCASE DIGIT-CHAR CHAR-INT INT-CHAR
  3796.                  CHAR-NAME CHAR-BIT
  3797.                  SPECIAL-FORM-P
  3798.                  ENDP
  3799.                  IDENTITY
  3800.                  EQ EQL CONSP ATOM SYMBOLP STRINGP NUMBERP
  3801.                  NULL NOT SYSTEM::CLOSUREP LISTP INTEGERP SYSTEM::FIXNUMP RATIONALP FLOATP
  3802.                  SYSTEM::SHORT-FLOAT-P SYSTEM::SINGLE-FLOAT-P SYSTEM::DOUBLE-FLOAT-P SYSTEM::LONG-FLOAT-P
  3803.                  REALP COMPLEXP STREAMP RANDOM-STATE-P READTABLEP HASH-TABLE-P PATHNAMEP CHARACTERP
  3804.                  PACKAGEP ARRAYP SIMPLE-ARRAY-P BIT-VECTOR-P VECTORP SIMPLE-VECTOR-P
  3805.                  SIMPLE-STRING-P SIMPLE-BIT-VECTOR-P SYSTEM::SYMBOL-MACRO-P CLOS::STD-INSTANCE-P
  3806.                  ZEROP PLUSP MINUSP ODDP EVENP = /= < > <= >= MAX MIN
  3807.                  + - * / 1+ 1- CONJUGATE GCD LCM ISQRT
  3808.                  RATIONAL RATIONALIZE NUMERATOR DENOMINATOR FLOOR CEILING TRUNCATE
  3809.                  ROUND MOD REM DECODE-FLOAT SCALE-FLOAT
  3810.                  FLOAT-RADIX FLOAT-SIGN FLOAT-DIGITS FLOAT-PRECISION INTEGER-DECODE-FLOAT
  3811.                  COMPLEX REALPART IMAGPART LOGIOR LOGXOR LOGAND LOGEQV LOGNAND LOGNOR
  3812.                  LOGANDC1 LOGANDC2 LOGORC1 LOGORC2 BOOLE LOGNOT LOGTEST LOGBITP ASH LOGCOUNT
  3813.                  INTEGER-LENGTH LDB LDB-TEST MASK-FIELD DPB DEPOSIT-FIELD ! EXQUO
  3814.                 ) ; alle diese sind SUBRs ohne Keyword-Parameter
  3815.                 (setq foldable t)
  3816.                 '(NIL . NIL)
  3817.                )
  3818.                ((VECTOR MAKE-STRING
  3819.                  VALUES ; nicht foldable, um Endlosschleife zu verhindern!
  3820.                  CONS LIST LIST* MAKE-LIST ACONS
  3821.                  LISP-IMPLEMENTATION-TYPE LISP-IMPLEMENTATION-VERSION SOFTWARE-TYPE
  3822.                  SOFTWARE-VERSION
  3823.                  SYSTEM::MAKE-LOAD-TIME-EVAL
  3824.                  SYMBOL-NAME
  3825.                  SYSTEM::DECIMAL-STRING
  3826.                 )
  3827.                 '(NIL . NIL)
  3828.                )
  3829.                ((SYSTEM::SUBR-INFO
  3830.                  AREF SVREF ARRAY-DIMENSION ARRAY-DIMENSIONS ARRAY-TOTAL-SIZE
  3831.                  ARRAY-IN-BOUNDS-P ARRAY-ROW-MAJOR-INDEX BIT SBIT
  3832.                  ARRAY-HAS-FILL-POINTER-P FILL-POINTER MAKE-ARRAY
  3833.                  CHARACTER CHAR SCHAR STRING= STRING/= STRING< STRING> STRING<=
  3834.                  STRING>= STRING-EQUAL STRING-NOT-EQUAL STRING-LESSP STRING-GREATERP
  3835.                  STRING-NOT-GREATERP STRING-NOT-LESSP SYSTEM::SEARCH-STRING=
  3836.                  SYSTEM::SEARCH-STRING-EQUAL SYSTEM::STRING-BOTH-TRIM STRING-UPCASE
  3837.                  STRING-DOWNCASE STRING-CAPITALIZE STRING NAME-CHAR SUBSTRING STRING-CONCAT
  3838.                  MAKE-SYMBOL SYMBOL-VALUE SYMBOL-FUNCTION BOUNDP FBOUNDP
  3839.                  VALUES-LIST MACRO-FUNCTION CONSTANTP
  3840.                  MAKE-HASH-TABLE GETHASH HASH-TABLE-COUNT SYSTEM::HASH-TABLE-ITERATOR SXHASH
  3841.                  GET-MACRO-CHARACTER GET-DISPATCH-MACRO-CHARACTER SYSTEM::LINE-POSITION
  3842.                  CAR CDR CAAR CADR CDAR CDDR CAAAR CAADR CADAR CADDR CDAAR CDADR CDDAR CDDDR
  3843.                  CAAAAR CAAADR CAADAR CAADDR CADAAR CADADR CADDAR CADDDR
  3844.                  CDAAAR CDAADR CDADAR CDADDR CDDAAR CDDADR CDDDAR CDDDDR
  3845.                  LIST-LENGTH NTH FIRST SECOND THIRD FOURTH FIFTH SIXTH SEVENTH
  3846.                  EIGHTH NINTH TENTH REST NTHCDR LAST APPEND COPY-LIST
  3847.                  COPY-ALIST COPY-TREE REVAPPEND BUTLAST LDIFF TAILP PAIRLIS
  3848.                  GET-UNIVERSAL-TIME GET-INTERNAL-RUN-TIME
  3849.                  GET-INTERNAL-REAL-TIME SYSTEM::%%TIME
  3850.                  FIND-PACKAGE PACKAGE-NAME PACKAGE-NICKNAMES PACKAGE-USE-LIST
  3851.                  PACKAGE-USED-BY-LIST PACKAGE-SHADOWING-SYMBOLS LIST-ALL-PACKAGES FIND-SYMBOL
  3852.                  FIND-ALL-SYMBOLS
  3853.                  PARSE-NAMESTRING PATHNAME PATHNAME-HOST PATHNAME-DEVICE PATHNAME-DIRECTORY
  3854.                  PATHNAME-NAME PATHNAME-TYPE PATHNAME-VERSION FILE-NAMESTRING
  3855.                  DIRECTORY-NAMESTRING HOST-NAMESTRING MERGE-PATHNAMES ENOUGH-NAMESTRING
  3856.                  MAKE-PATHNAME NAMESTRING TRUENAME PROBE-FILE DIRECTORY FILE-WRITE-DATE
  3857.                  FILE-AUTHOR
  3858.                  EQUAL EQUALP COMPILED-FUNCTION-P FUNCTIONP CLOS::GENERIC-FUNCTION-P COMMONP
  3859.                  TYPE-OF CLOS::CLASS-P CLOS:CLASS-OF COERCE
  3860.                  SYSTEM::%RECORD-REF SYSTEM::%RECORD-LENGTH SYSTEM::%STRUCTURE-REF SYSTEM::%MAKE-STRUCTURE
  3861.                  SYSTEM::%COPY-STRUCTURE SYSTEM::%STRUCTURE-TYPE-P SYSTEM::CLOSURE-NAME
  3862.                  SYSTEM::CLOSURE-CODEVEC SYSTEM::CLOSURE-CONSTS SYSTEM::MAKE-CODE-VECTOR
  3863.                  SYSTEM::%MAKE-CLOSURE SYSTEM::MAKE-LOAD-TIME-EVAL SYSTEM::MAKE-SYMBOL-MACRO
  3864.                  CLOS::ALLOCATE-STD-INSTANCE CLOS:SLOT-EXISTS-P
  3865.                  SYSTEM::SEQUENCEP ELT SUBSEQ COPY-SEQ LENGTH REVERSE CONCATENATE
  3866.                  MAKE-SYNONYM-STREAM MAKE-BROADCAST-STREAM MAKE-CONCATENATED-STREAM
  3867.                  MAKE-TWO-WAY-STREAM MAKE-ECHO-STREAM MAKE-STRING-INPUT-STREAM
  3868.                  SYSTEM::STRING-INPUT-STREAM-INDEX MAKE-STRING-OUTPUT-STREAM
  3869.                  SYSTEM::MAKE-STRING-PUSH-STREAM MAKE-BUFFERED-INPUT-STREAM
  3870.                  MAKE-BUFFERED-OUTPUT-STREAM INPUT-STREAM-P OUTPUT-STREAM-P
  3871.                  STREAM-ELEMENT-TYPE FILE-LENGTH
  3872.                  GET GETF GET-PROPERTIES SYMBOL-PACKAGE SYMBOL-PLIST KEYWORDP
  3873.                  SYSTEM::SPECIAL-VARIABLE-P GENSYM
  3874.                  FFLOOR FCEILING FTRUNCATE FROUND
  3875.                  EXP EXPT LOG SQRT ABS PHASE SIGNUM SIN COS TAN CIS ASIN ACOS ATAN
  3876.                  SINH COSH TANH ASINH ACOSH ATANH FLOAT BYTE BYTE-SIZE BYTE-POSITION
  3877.                  SYSTEM::LOG2 SYSTEM::LOG10
  3878.                 )
  3879.                 '(T . NIL)
  3880.                )
  3881.                (t '(T . T)) ; vielleicht Seiteneffekte
  3882.         )) ) )
  3883.     (if (and (null *for-value*) (null (cdr sideeffects)))
  3884.       ; Brauche die Funktion nicht aufzurufen, nur die Argumente auswerten
  3885.       (progn
  3886.         (let ((*no-code* t) (*for-value* 'NIL))
  3887.           (funcall call-code-producer)
  3888.         )
  3889.         (c-form `(PROGN ,@args ,@applyargs))
  3890.       )
  3891.       (let ((n (length args))
  3892.             (reqopt (+ req opt))
  3893.             (seclass sideeffects)
  3894.             (codelist '()))
  3895.         (let ((*stackz* *stackz*))
  3896.           ; required und angegebene optionale Parameter:
  3897.           (dotimes (i (min n reqopt))
  3898.             (let* ((formi (pop args))
  3899.                    (anodei (c-form formi 'ONE)))
  3900.               (seclass-or-f seclass anodei)
  3901.               (push anodei codelist)
  3902.             )
  3903.             (push '(PUSH) codelist)
  3904.             (push 1 *stackz*)
  3905.           )
  3906.           (if applyargs
  3907.             (progn
  3908.               (when subr-flag (compiler-error 'c-DIRECT-FUNCTION-CALL "APPLY-SUBR"))
  3909.               (when key-p (compiler-error 'c-DIRECT-FUNCTION-CALL "APPLY-KEY"))
  3910.               (if (>= reqopt n)
  3911.                 ; fehlende optionale Parameter werden aus der Liste initialisiert:
  3912.                 (let* ((anz (- reqopt n))
  3913.                        (anode1 (c-form (first applyargs) 'ONE))
  3914.                        (anode2 (progn
  3915.                                  (push (if rest-p (+ anz 1) anz) *stackz*)
  3916.                                  (c-unlist rest-p anz (min opt anz))
  3917.                       ))       )
  3918.                   (seclass-or-f seclass anode1)
  3919.                   (push anode1 codelist)
  3920.                   (seclass-or-f seclass anode2)
  3921.                   (push anode2 codelist)
  3922.                 )
  3923.                 ; n > reqopt, impliziert rest-p.
  3924.                 ; Übergabe von restlichen Argumenten an eine compilierte Closure:
  3925.                 ; als Liste.
  3926.                 ; Liste aus allen weiteren Argumenten:
  3927.                 (progn
  3928.                   (let ((*stackz* *stackz*)
  3929.                         (rest-args args))
  3930.                     (loop
  3931.                       (when (null rest-args) (return))
  3932.                       (let ((anode (c-form (pop rest-args) 'ONE)))
  3933.                         (seclass-or-f seclass anode)
  3934.                         (push anode codelist)
  3935.                       )
  3936.                       (push '(PUSH) codelist)
  3937.                       (push 1 *stackz*)
  3938.                     )
  3939.                     (let ((anode (c-form (first applyargs) 'ONE)))
  3940.                       (seclass-or-f seclass anode)
  3941.                       (push anode codelist)
  3942.                     )
  3943.                     (push `(LIST* ,(- n reqopt)) codelist)
  3944.                   )
  3945.                   (push '(PUSH) codelist)
  3946.                   (push 1 *stackz*)
  3947.             ) ) )
  3948.             (progn
  3949.               ; fehlende optionale Parameter werden mit #<UNBOUND> initialisiert:
  3950.               (when (> reqopt n)
  3951.                 (let ((anz (- reqopt n)))
  3952.                   (push `(PUSH-UNBOUND ,anz) codelist)
  3953.                   (push anz *stackz*)
  3954.               ) )
  3955.               ; &rest-Parameter:
  3956.               (when rest-p
  3957.                 (if subr-flag
  3958.                   ; Übergabe von restlichen Argumenten an ein SUBR: einzeln
  3959.                   (loop
  3960.                     (when (null args) (return))
  3961.                     (let ((anode (c-form (pop args) 'ONE)))
  3962.                       (seclass-or-f seclass anode)
  3963.                       (push anode codelist)
  3964.                     )
  3965.                     (push '(PUSH) codelist)
  3966.                     (push 1 *stackz*)
  3967.                   )
  3968.                   ; Übergabe von restlichen Argumenten an eine compilierte Closure:
  3969.                   ; als Liste
  3970.                   (if (null args)
  3971.                     ; leere Liste
  3972.                     (progn
  3973.                       (push '(NIL) codelist)
  3974.                       (push '(PUSH) codelist)
  3975.                       (push 1 *stackz*)
  3976.                     )
  3977.                     ; Liste aus allen weiteren Argumenten:
  3978.                     (progn
  3979.                       (let ((*stackz* *stackz*)
  3980.                             (rest-args args))
  3981.                         (loop
  3982.                           (when (null rest-args) (return))
  3983.                           (let ((anode (c-form (pop rest-args) 'ONE)))
  3984.                             (seclass-or-f seclass anode)
  3985.                             (push anode codelist)
  3986.                           )
  3987.                           (push '(PUSH) codelist)
  3988.                           (push 1 *stackz*)
  3989.                         )
  3990.                         (push `(LIST ,(- n reqopt)) codelist)
  3991.                       )
  3992.                       (push '(PUSH) codelist)
  3993.                       (push 1 *stackz*)
  3994.             ) ) ) ) )
  3995.           )
  3996.           ; &key-Parameter:
  3997.           (when key-p
  3998.             ; Nur dann gleichzeitig rest-p und key-p, wenn n <= reqopt, da
  3999.             ; test-argument-syntax (ergab STATIC-KEYS) den anderen Fall
  4000.             ; bereits ausgeschlossen hat.
  4001.             (let ((keyanz (length keylist)))
  4002.               ; Erst alle Keys mit #<UNBOUND> vorbelegen, dann die Argumente
  4003.               ; in der angegebenen Reihenfolge auswerten und zuordnen?
  4004.               ; Das ist uns zu einfach. Wir lassen die Argumente kommutieren,
  4005.               ; damit möglichst viele der (STORE ...) durch (PUSH) ersetzt
  4006.               ; werden können: Die Argumente zu den ersten Keys werden nach
  4007.               ; Möglichkeit zuerst ausgewertet, die zu den letzten Keys
  4008.               ; zuletzt. Wir lassen es allerdings bei einem einzigen
  4009.               ; (PUSH-UNBOUND ...).
  4010.               (let* ((key-positions ; Liste von Tripeln (key stack-depth free-p),
  4011.                                     ; wobei stack-depth = keyanz-1...0 läuft und
  4012.                                     ; free-p angibt, ob der Slot schon gefüllt ist.
  4013.                        (let ((i keyanz))
  4014.                          (mapcar #'(lambda (key) (list key (decf i) t)) keylist)
  4015.                      ) )
  4016.                      (anodes ; Liste von Quadrupeln
  4017.                              ; (needed key-position anode stackz), wobei
  4018.                              ; key-position die stack-depth des Keyword-Slots
  4019.                              ; oder NIL ist, anode der Anode zu diesem Argument.
  4020.                              ; Die Liste wird in derselben Reihenfolge gehalten,
  4021.                              ; wie sie die Argumentliste vorgibt.
  4022.                              ; Ausnahme: needed = NIL bei anodes, deren
  4023.                              ; Berechnung man vorgezogen oder verschoben hat.
  4024.                        (let ((L '()))
  4025.                          (loop
  4026.                            (when (null args) (return))
  4027.                            (let* ((key (c-constant-value (pop args)))
  4028.                                   (tripel (assoc key key-positions :test #'eq)) ; kann =NIL sein!
  4029.                                   (for-value (third tripel))
  4030.                                   (arg (pop args)))
  4031.                              ; for-value /= NIL: Existentes Keyword, und der Slot ist noch leer
  4032.                              ; for-value = NIL: ALLOW-erlaubtes Keyword oder Slot schon gefüllt
  4033.                              (let* ((*stackz* (cons 0 *stackz*)) ; 0 wird später ersetzt
  4034.                                     (anode (c-form arg (if for-value 'ONE 'NIL))))
  4035.                                (seclass-or-f seclass anode)
  4036.                                (push (list t (second tripel) anode *stackz*) L)
  4037.                              )
  4038.                              (setf (third tripel) nil)
  4039.                          ) )
  4040.                          (nreverse L)
  4041.                     )) )
  4042.                 (let ((depth1 0)
  4043.                       (depth2 0)
  4044.                       (codelist-from-end '()))
  4045.                   ; Möglichst viel nach vorne ziehen:
  4046.                   (do ((anodesr anodes (cdr anodesr)))
  4047.                       ((null anodesr))
  4048.                     (let ((anodeetc (car anodesr))) ; nächstes Quadrupel
  4049.                       (when (first anodeetc) ; noch was zu tun?
  4050.                         (if (and
  4051.                               (or ; kein Keyword, d.h. kein (STORE ...) nötig?
  4052.                                   (null (second anodeetc))
  4053.                                   ; oberstes Keyword?
  4054.                                   (= (second anodeetc) (- keyanz depth1 1))
  4055.                               )
  4056.                               ; kommutiert anodeetc mit allen vorigen anodes?
  4057.                               (let ((anode (third anodeetc)))
  4058.                                 (do ((anodesr2 anodes (cdr anodesr2)))
  4059.                                     ((eq anodesr2 anodesr) t)
  4060.                                   (unless (anodes-commute anode (third (car anodesr2)))
  4061.                                     (return nil)
  4062.                               ) ) )
  4063.                             )
  4064.                           ; vorziehen:
  4065.                           (progn
  4066.                             (setf (first (fourth anodeetc)) depth1) ; korrekte Stacktiefe
  4067.                             (push (third anodeetc) codelist) ; in die Codeliste
  4068.                             (when (second anodeetc)
  4069.                               (push '(PUSH) codelist)
  4070.                               (incf depth1)
  4071.                             )
  4072.                             (setf (first anodeetc) nil) ; diesen brauchen wir nicht mehr
  4073.                           )
  4074.                           ; sonst machen wir nichts.
  4075.                   ) ) ) )
  4076.                   ; Möglichst viel nach hinten ziehen:
  4077.                   (setq anodes (nreverse anodes))
  4078.                   (do ((anodesr anodes (cdr anodesr)))
  4079.                       ((null anodesr))
  4080.                     (let ((anodeetc (car anodesr))) ; nächstes Quadrupel
  4081.                       (when (first anodeetc) ; noch was zu tun?
  4082.                         (if (and
  4083.                               (or ; kein Keyword, d.h. kein (STORE ...) nötig?
  4084.                                   (null (second anodeetc))
  4085.                                   ; unterstes Keyword?
  4086.                                   (= (second anodeetc) depth2)
  4087.                               )
  4088.                               ; kommutiert anodeetc mit allen späteren anodes?
  4089.                               (let ((anode (third anodeetc)))
  4090.                                 (do ((anodesr2 anodes (cdr anodesr2)))
  4091.                                     ((eq anodesr2 anodesr) t)
  4092.                                   (unless (anodes-commute anode (third (car anodesr2)))
  4093.                                     (return nil)
  4094.                               ) ) )
  4095.                             )
  4096.                           ; ans Ende verschieben:
  4097.                           (progn
  4098.                             (when (second anodeetc)
  4099.                               (push '(PUSH) codelist-from-end)
  4100.                               (incf depth2)
  4101.                             )
  4102.                             (setf (first (fourth anodeetc)) (- keyanz depth2)) ; korrekte Stacktiefe
  4103.                             (push (third anodeetc) codelist-from-end) ; in die Codeliste
  4104.                             (setf (first anodeetc) nil) ; diesen brauchen wir nicht mehr
  4105.                           )
  4106.                           ; sonst machen wir nichts.
  4107.                   ) ) ) )
  4108.                   (setq anodes (nreverse anodes))
  4109.                   (let ((depth-now (- keyanz depth2))) ; codelist-from-end erniedrigt den Stack um depth2
  4110.                     (when (> depth-now depth1)
  4111.                       (push `(PUSH-UNBOUND ,(- depth-now depth1)) codelist)
  4112.                     )
  4113.                     ; In codelist herrscht jetzt Stacktiefe depth-now.
  4114.                     (dolist (anodeetc anodes)
  4115.                       (when (first anodeetc)
  4116.                         (setf (first (fourth anodeetc)) depth-now) ; korrekte Stacktiefe
  4117.                         (push (third anodeetc) codelist)
  4118.                         (when (second anodeetc)
  4119.                           (push `(STORE ,(- (second anodeetc) depth2)) codelist)
  4120.                   ) ) ) )
  4121.                   ; Nun codelist-from-end:
  4122.                   (setq codelist (nreconc codelist-from-end codelist))
  4123.               ) )
  4124.               ; Jetzt sind alle Key-Argumente auf dem Stack.
  4125.               (push keyanz *stackz*)
  4126.           ) )
  4127.           (setq codelist (nreconc codelist (funcall call-code-producer)))
  4128.         )
  4129.         ; Constant-Folding: Ist fun foldable (also subr-flag = T und
  4130.         ; key-flag = NIL) und besteht codelist außer den (PUSH)s und dem
  4131.         ; Call-Code am Schluß nur aus Anodes mit code = ((CONST ...)) ?
  4132.         (when (and foldable
  4133.                    (every #'(lambda (code)
  4134.                               (or (not (anode-p code)) (anode-constantp code))
  4135.                             )
  4136.                           codelist
  4137.               )    )
  4138.           ; Funktion aufzurufen versuchen:
  4139.           (let ((args (let ((L '())) ; Liste der (konstanten) Argumente
  4140.                         (dolist (code codelist)
  4141.                           (when (anode-p code)
  4142.                             (push (anode-constant-value code) L)
  4143.                         ) )
  4144.                         (nreverse L)
  4145.                 )     )
  4146.                 resulting-values)
  4147.             (when (block try-eval
  4148.                     (setq resulting-values
  4149.                       (let ((*error-handler*
  4150.                               #'(lambda (&rest error-args)
  4151.                                   (declare (ignore error-args))
  4152.                                   (return-from try-eval nil)
  4153.                            ))   )
  4154.                         (multiple-value-list (apply fun args))
  4155.                     ) )
  4156.                     t
  4157.                   )
  4158.               ; Funktion erfolgreich aufgerufen, Constant-Folding durchführen:
  4159.               (return-from c-DIRECT-FUNCTION-CALL
  4160.                 (c-GLOBAL-FUNCTION-CALL-form
  4161.                   `(VALUES ,@(mapcar #'(lambda (x) `(QUOTE ,x)) resulting-values))
  4162.         ) ) ) ) )
  4163.         (make-anode
  4164.           :type `(DIRECT-CALL ,fun)
  4165.           :sub-anodes (remove-if-not #'anode-p codelist)
  4166.           :seclass seclass
  4167.           :code codelist
  4168.         )
  4169. ) ) ) )
  4170. (defun c-unlist (rest-p n m)
  4171.   (if rest-p
  4172.     (if (eql n 0)
  4173.       (make-anode :type 'UNLIST*
  4174.                   :sub-anodes '()
  4175.                   :seclass '(NIL . NIL)
  4176.                   :code '((PUSH))
  4177.       )
  4178.       (make-anode :type 'UNLIST*
  4179.                   :sub-anodes '()
  4180.                   :seclass '(T . T) ; kann Error melden
  4181.                   :code `((UNLIST* ,n ,m))
  4182.     ) )
  4183.     (make-anode :type 'UNLIST
  4184.                 :sub-anodes '()
  4185.                 :seclass '(T . T) ; kann Error melden
  4186.                 :code `((UNLIST ,n ,m))
  4187. ) ) )
  4188. (defun cclosure-call-code-producer (fun fnode req opt rest-flag key-flag keylist)
  4189.   (if (eq fnode *func*)
  4190.     ; rekursiver Aufruf der eigenen Funktion
  4191.     (let ((call-code
  4192.             `((JSR ,(+ req opt (if rest-flag 1 0) (length keylist)) ; Zahl der Stack-Einträge
  4193.                    ,*func-start-label*
  4194.              ))
  4195.          ))
  4196.       #'(lambda () call-code)
  4197.     )
  4198.     ; eine andere Cclosure aufrufen
  4199.     #'(lambda ()
  4200.         (list
  4201.           (c-form `(FUNCTION ,fun) 'ONE)
  4202.           (if key-flag '(CALLCKEY) '(CALLC))
  4203.       ) )
  4204. ) )
  4205.  
  4206. ; Global function call: (fun {form}*)
  4207. (defun c-GLOBAL-FUNCTION-CALL-form (*form*)
  4208.   (c-GLOBAL-FUNCTION-CALL (first *form*))
  4209. )
  4210. (defun c-GLOBAL-FUNCTION-CALL (fun) ; fun ist ein Symbol oder (SETF symbol)
  4211.   (test-list *form* 1)
  4212.   (when *compiling-from-file* ; von COMPILE-FILE aufgerufen?
  4213.     (unless (or (fboundp fun) (member fun *known-functions* :test #'equal))
  4214.       (pushnew fun *unknown-functions* :test #'equal)
  4215.     )
  4216.     ; PROCLAIM-Deklarationen zur Kenntnis nehmen:
  4217.     (when (and (eq fun 'PROCLAIM) (= (length *form*) 2))
  4218.       (let ((h (second *form*)))
  4219.         (when (c-constantp h)
  4220.           (c-form
  4221.             `(EVAL-WHEN (COMPILE) (c-PROCLAIM ',(c-constant-value h)))
  4222.     ) ) ) )
  4223.     ; Modul-Anforderungen zur Kenntnis nehmen:
  4224.     (when (and (memq fun '(PROVIDE REQUIRE))
  4225.                (every #'c-constantp (rest *form*))
  4226.           )
  4227.       (c-form
  4228.         `(EVAL-WHEN (COMPILE)
  4229.            (,(case fun
  4230.                (PROVIDE 'c-PROVIDE) ; c-PROVIDE statt PROVIDE
  4231.                (REQUIRE 'c-REQUIRE) ; c-REQUIRE statt REQUIRE
  4232.              )
  4233.             ,@(mapcar
  4234.                 #'(lambda (x) (list 'QUOTE (c-constant-value x))) ; Argumente quotieren
  4235.                 (rest *form*)
  4236.          ) )  )
  4237.     ) )
  4238.     ; Package-Anforderungen zur Kenntnis nehmen:
  4239.     (when (and (memq fun '(MAKE-PACKAGE IN-PACKAGE SHADOW SHADOWING-IMPORT
  4240.                            EXPORT UNEXPORT USE-PACKAGE UNUSE-PACKAGE IMPORT
  4241.                )          )
  4242.                (every #'c-constantp (rest *form*))
  4243.           )
  4244.       (push
  4245.         `(,fun
  4246.           ,@(mapcar
  4247.               #'(lambda (x) (list 'QUOTE (c-constant-value x))) ; Argumente quotieren
  4248.               (rest *form*)
  4249.          )  )
  4250.         *package-tasks*
  4251.   ) ) )
  4252.   (let* ((args (cdr *form*)) ; Argumente
  4253.          (n (length args))) ; Anzahl der Argumente
  4254.     (if (not (declared-notinline fun)) ; darf fun INLINE genommen werden?
  4255.       (multiple-value-bind (name req opt rest-p keylist allow-p) (subr-info fun)
  4256.         ; Ist fun ein SUBR, so sollte name = fun sein, und das SUBR hat die
  4257.         ; Spezifikation req, opt, rest-p, key-p = (not (null keylist)), allow-p.
  4258.         ; Sonst ist name = NIL.
  4259.         (if (and name (eq fun name)) ; beschreibt fun ein gültiges SUBR?
  4260.           (case fun
  4261.             ((CAR CDR FIRST REST NOT NULL CONS SVREF VALUES
  4262.               CAAR CADR CDAR CDDR CAAAR CAADR CADAR CADDR CDAAR CDADR
  4263.               CDDAR CDDDR SECOND THIRD FOURTH CAAAAR CAAADR CAADAR CAADDR
  4264.               CADAAR CADADR CADDAR CADDDR CDAAAR CDAADR CDADAR CDADDR
  4265.               CDDAAR CDDADR CDDDAR CDDDDR ATOM CONSP
  4266.               VALUES-LIST SYS::%SVSTORE EQ SYMBOL-FUNCTION LIST LIST* ERROR
  4267.              )
  4268.              ; Diese hier haben keylist=NIL, allow-p=NIL und
  4269.              ; (was aber nicht verwendet wird) opt=0.
  4270.              (if (and (<= req n) (or rest-p (<= n (+ req opt))))
  4271.                ; Wir machen den Aufruf INLINE.
  4272.                (let ((sideeffects ; Seiteneffektklasse der Funktionsausführung
  4273.                        (case fun
  4274.                          ((NOT NULL CONS VALUES ATOM CONSP EQ LIST LIST*)
  4275.                            '(NIL . NIL)
  4276.                          )
  4277.                          ((CAR CDR FIRST REST CAAR CADR
  4278.                            CDAR CDDR CAAAR CAADR CADAR CADDR CDAAR CDADR CDDAR
  4279.                            CDDDR SECOND THIRD FOURTH CAAAAR CAAADR CAADAR CAADDR
  4280.                            CADAAR CADADR CADDAR CADDDR CDAAAR CDAADR CDADAR CDADDR
  4281.                            CDDAAR CDDADR CDDDAR CDDDDR VALUES-LIST
  4282.                            SVREF SYMBOL-FUNCTION
  4283.                           )
  4284.                            '(T . NIL)
  4285.                          )
  4286.                          (t '(T . T))
  4287.                     )) )
  4288.                  (if (and (null *for-value*) (null (cdr sideeffects)))
  4289.                    ; Brauche die Funktion nicht aufzurufen, nur die Argumente auswerten
  4290.                    (c-form `(PROGN ,@args))
  4291.                    (if (and (eq fun 'VALUES) (eq *for-value* 'ONE))
  4292.                      (if (= n 0) (c-NIL) (c-form `(PROG1 ,@args)))
  4293.                      (let ((seclass sideeffects)
  4294.                            (codelist '()))
  4295.                        (let ((*stackz* *stackz*))
  4296.                          ; Argumente auswerten und bis auf das letzte auf den Stack
  4297.                          ; (denn das letzte Argument wird in A0 erwartet):
  4298.                          (loop
  4299.                            (when (null args) (return))
  4300.                            (let ((anode (c-form (pop args) 'ONE)))
  4301.                              (seclass-or-f seclass anode)
  4302.                              (push anode codelist)
  4303.                            )
  4304.                            (when args ; nicht am Schluß
  4305.                              (push '(PUSH) codelist)
  4306.                              (push 1 *stackz*)
  4307.                          ) )
  4308.                          (setq codelist
  4309.                            (nreconc codelist
  4310.                              (case fun
  4311.                                ((CAR FIRST) '((CAR)))
  4312.                                ((CDR REST) '((CDR)))
  4313.                                (CAAR '((CAR) (CAR)))
  4314.                                ((CADR SECOND) '((CDR) (CAR)))
  4315.                                (CDAR '((CAR) (CDR)))
  4316.                                (CDDR '((CDR) (CDR)))
  4317.                                (CAAAR '((CAR) (CAR) (CAR)))
  4318.                                (CAADR '((CDR) (CAR) (CAR)))
  4319.                                (CADAR '((CAR) (CDR) (CAR)))
  4320.                                ((CADDR THIRD) '((CDR) (CDR) (CAR)))
  4321.                                (CDAAR '((CAR) (CAR) (CDR)))
  4322.                                (CDADR '((CDR) (CAR) (CDR)))
  4323.                                (CDDAR '((CAR) (CDR) (CDR)))
  4324.                                (CDDDR '((CDR) (CDR) (CDR)))
  4325.                                (CAAAAR '((CAR) (CAR) (CAR) (CAR)))
  4326.                                (CAAADR '((CDR) (CAR) (CAR) (CAR)))
  4327.                                (CAADAR '((CAR) (CDR) (CAR) (CAR)))
  4328.                                (CAADDR '((CDR) (CDR) (CAR) (CAR)))
  4329.                                (CADAAR '((CAR) (CAR) (CDR) (CAR)))
  4330.                                (CADADR '((CDR) (CAR) (CDR) (CAR)))
  4331.                                (CADDAR '((CAR) (CDR) (CDR) (CAR)))
  4332.                                ((CADDDR FOURTH) '((CDR) (CDR) (CDR) (CAR)))
  4333.                                (CDAAAR '((CAR) (CAR) (CAR) (CDR)))
  4334.                                (CDAADR '((CDR) (CAR) (CAR) (CDR)))
  4335.                                (CDADAR '((CAR) (CDR) (CAR) (CDR)))
  4336.                                (CDADDR '((CDR) (CDR) (CAR) (CDR)))
  4337.                                (CDDAAR '((CAR) (CAR) (CDR) (CDR)))
  4338.                                (CDDADR '((CDR) (CAR) (CDR) (CDR)))
  4339.                                (CDDDAR '((CAR) (CDR) (CDR) (CDR)))
  4340.                                (CDDDDR '((CDR) (CDR) (CDR) (CDR)))
  4341.                                (ATOM '((ATOM)))
  4342.                                (CONSP '((CONSP)))
  4343.                                ((NOT NULL) '((NOT)))
  4344.                                (CONS '((CONS)))
  4345.                                (SVREF '((SVREF)))
  4346.                                (SYS::%SVSTORE '((SVSET)))
  4347.                                (EQ '((EQ)))
  4348.                                (VALUES (case n
  4349.                                          (0 '((VALUES0)) )
  4350.                                          (1 '((VALUES1)) )
  4351.                                          (t `((PUSH) ; letztes Argument auch noch in den Stack
  4352.                                               (STACK-TO-MV ,n)
  4353.                                              )
  4354.                                )       ) )
  4355.                                (VALUES-LIST '((LIST-TO-MV)))
  4356.                                (SYMBOL-FUNCTION '((SYMBOL-FUNCTION)))
  4357.                                (LIST (if (plusp n)
  4358.                                        `((PUSH) (LIST ,n))
  4359.                                        '((NIL))
  4360.                                )     )
  4361.                                (LIST* (case n
  4362.                                         (1 '((VALUES1)) )
  4363.                                         (t `((LIST* ,(1- n))) )
  4364.                                )      )
  4365.                                (ERROR `((PUSH) (ERROR ,(1- n))))
  4366.                                (t (compiler-error 'c-GLOBAL-FUNCTION-CALL))
  4367.                        ) ) ) )
  4368.                        (make-anode
  4369.                          :type `(PRIMOP ,fun)
  4370.                          :sub-anodes (remove-if-not #'anode-p codelist)
  4371.                          :seclass seclass
  4372.                          :code codelist
  4373.                        )
  4374.                ) ) ) )
  4375.                ; falsche Argumentezahl -> doch nicht INLINE:
  4376.                (progn
  4377.                  (c-warn #+DEUTSCH "~S mit ~S Argumenten aufgerufen, braucht aber ~
  4378.                                     ~:[~:[~S bis ~S~;~S~]~;mindestens ~*~S~] Argumente."
  4379.                          #+ENGLISH "~S called with ~S arguments, but it requires ~
  4380.                                     ~:[~:[from ~S to ~S~;~S~]~;at least ~*~S~] arguments."
  4381.                          fun n
  4382.                          rest-p  (eql opt 0) req (+ req opt)
  4383.                  )
  4384.                  (c-NORMAL-FUNCTION-CALL fun)
  4385.             )) )
  4386.             (t ; Ist das SUBR fun in der FUNTAB enthalten?
  4387.              (let ((index (gethash fun function-codes)))
  4388.                (if index
  4389.                  (case (test-argument-syntax args nil
  4390.                                     fun req opt rest-p keylist keylist allow-p
  4391.                        )
  4392.                    ((NO-KEYS STATIC-KEYS)
  4393.                     ; korrekte Syntax, Stack-Layout zur Compilezeit vorhersehbar
  4394.                     ; -> INLINE
  4395.                     (c-DIRECT-FUNCTION-CALL
  4396.                       args nil fun req opt rest-p keylist keylist
  4397.                       t ; es handelt sich um ein SUBR
  4398.                       (let ((call-code
  4399.                               ; Aufruf mit Hilfe der FUNTAB:
  4400.                               (if (not rest-p)
  4401.                                 (list (CALLS-code index))
  4402.                                 `((CALLSR ,(max 0 (- n req opt)) ; Bei n<req+opt kommt noch ein (PUSH-UNBOUND ...)
  4403.                                           ,(- index funtabR-index)
  4404.                                  ))
  4405.                            )) )
  4406.                         #'(lambda () call-code)
  4407.                    )) )
  4408.                    (t (c-NORMAL-FUNCTION-CALL fun))
  4409.                  )
  4410.                  (c-NORMAL-FUNCTION-CALL fun)
  4411.           ) )) )
  4412.           (let ((inline-lambdabody
  4413.                   (or (and *compiling-from-file*
  4414.                            (cdr (assoc fun *inline-definitions* :test #'equal))
  4415.                       )
  4416.                       (get (get-funname-symbol fun) 'sys::inline-expansion)
  4417.                )) )
  4418.             (if (and #| inline-lambdabody |#
  4419.                      (consp inline-lambdabody)
  4420.                      (inline-callable-function-p `(FUNCTION (LAMBDA ,@inline-lambdabody)) n)
  4421.                 )
  4422.               ; Aufruf einer globalen Funktion INLINE möglich
  4423.               (c-FUNCALL-INLINE fun args nil inline-lambdabody nil)
  4424.               (c-NORMAL-FUNCTION-CALL fun)
  4425.       ) ) ) )
  4426.       (c-NORMAL-FUNCTION-CALL fun)
  4427. ) ) )
  4428.  
  4429. ; Hilfsfunktion: PROCLAIM beim Compilieren vom File, vgl. Funktion PROCLAIM
  4430. (defun c-PROCLAIM (declspec)
  4431.   (when (consp declspec)
  4432.     (case (car declspec)
  4433.       (SPECIAL
  4434.         (dolist (var (cdr declspec))
  4435.           (when (symbolp var) (pushnew var *known-special-vars* :test #'eq))
  4436.       ) )
  4437.       (INLINE
  4438.         (dolist (var (cdr declspec))
  4439.           (when (function-name-p var)
  4440.             (pushnew var *inline-functions* :test #'equal)
  4441.             (setq *notinline-functions* (delete var *notinline-functions* :test #'equal))
  4442.       ) ) )
  4443.       (NOTINLINE
  4444.         (dolist (var (cdr declspec))
  4445.           (when (function-name-p var)
  4446.             (pushnew var *notinline-functions* :test #'equal)
  4447.             (setq *inline-functions* (delete var *inline-functions* :test #'equal))
  4448.       ) ) )
  4449.       (DECLARATION
  4450.         (dolist (var (cdr declspec))
  4451.           (when (symbolp var) (pushnew var *user-declaration-types* :test #'eq))
  4452.       ) )
  4453. ) ) )
  4454.  
  4455. ; Hilfsfunktion: DEFCONSTANT beim Compilieren
  4456. (defun c-PROCLAIM-CONSTANT (symbol initial-value-form)
  4457.   (when *compiling-from-file*
  4458.     (pushnew symbol *known-special-vars* :test #'eq)
  4459.     (when (c-constantp initial-value-form)
  4460.       (push (cons symbol (c-constant-value initial-value-form))
  4461.             *constant-special-vars*
  4462. ) ) ) )
  4463.  
  4464. ; Hilfsfunktion: DEFUN beim Compilieren
  4465. (defun c-DEFUN (symbol &optional lambdabody)
  4466.   (when *compiling* ; c-DEFUN kann auch vom Expander aus aufgerufen werden!
  4467.     (when *compiling-from-file*
  4468.       (pushnew symbol *known-functions* :test #'equal)
  4469.       (when lambdabody ; Lambdabody angegeben ->
  4470.         ; Funktionsdefinition erfolgt im Top-Level-Environment und ist inlinebar.
  4471.         (push (cons symbol lambdabody) *inline-definitions*)
  4472. ) ) ) )
  4473.  
  4474. ; Hilfsfunktion: PROVIDE beim Compilieren vom File, vgl. Funktion PROVIDE
  4475. (defun c-PROVIDE (module-name)
  4476.   (pushnew (string module-name) *compiled-modules* :test #'string=)
  4477. )
  4478.  
  4479. ; Hilfsfunktion: REQUIRE beim Compilieren vom File, vgl. Funktion REQUIRE
  4480. (defun c-REQUIRE (module-name &optional (pathname nil p-given))
  4481.   (unless (member (string module-name) *compiled-modules* :test #'string-equal)
  4482.     (unless p-given (setq pathname (pathname module-name)))
  4483.     (flet ((load-lib (file)
  4484.              (let* ((present-files (search-file file '(#".lsp" #".lib")))
  4485.                     (newest-file (first present-files)))
  4486.                ; Maximal 2 Files gefunden. Falls das libfile unter diesen
  4487.                ; vorkommt und das neueste ist:
  4488.                (if (and (consp present-files)
  4489.                         (string= (pathname-type newest-file)
  4490.                                  '#,(pathname-type '#".lib")
  4491.                    )    )
  4492.                  (load newest-file :verbose nil :print nil :echo nil) ; libfile laden
  4493.                  (compile-file (or newest-file file)) ; file compilieren
  4494.           )) ) )
  4495.       (if (atom pathname) (load-lib pathname) (mapcar #'load-lib pathname))
  4496. ) ) )
  4497.  
  4498. ;;; Hilfsfunktionen für
  4499. ;;; LET/LET*/MULTIPLE-VALUE-BIND/Lambda-Ausdruck/FLET/LABELS:
  4500.  
  4501. ;; Syntaxanalyse:
  4502.  
  4503. ; analysiert eine Parameterliste von LET/LET*, liefert:
  4504. ; die Liste der Symbole,
  4505. ; die Liste der Formen.
  4506. (defun analyze-letlist (parameters)
  4507.   (do ((L parameters (cdr L))
  4508.        (symbols nil)
  4509.        (forms nil))
  4510.       ((null L) (values (nreverse symbols) (nreverse forms)))
  4511.     (cond ((symbolp (car L)) (push (car L) symbols) (push nil forms))
  4512.           ((and (consp (car L)) (symbolp (caar L))
  4513.                 (consp (cdar L)) (null (cddar L))
  4514.            )
  4515.            (push (caar L) symbols) (push (cadar L) forms)
  4516.           )
  4517.           (t (catch 'c-error
  4518.                (c-error #+DEUTSCH "Falsche Syntax in LET/LET*: ~S"
  4519.                         #+ENGLISH "Illegal syntax in LET/LET*: ~S"
  4520.                         (car L)
  4521.     )     )  ) )
  4522. ) )
  4523.  
  4524. ; analysiert eine Lambdaliste einer Funktion (CLTL S. 60), liefert 13 Werte:
  4525. ; 1. Liste der required Parameter
  4526. ; 2. Liste der optionalen Parameter
  4527. ; 3. Liste der Initformen der optionalen Parameter
  4528. ; 4. Liste der Svars zu den optionalen Parametern (0 für die fehlenden)
  4529. ; 5. Rest-Parameter oder 0
  4530. ; 6. Flag, ob Keywords erlaubt sind
  4531. ; 7. Liste der Keywords
  4532. ; 8. Liste der Keyword-Parameter
  4533. ; 9. Liste der Initformen der Keyword-Parameter
  4534. ; 10. Liste der Svars zu den Keyword-Parametern (0 für die fehlenden)
  4535. ; 11. Flag, ob andere Keywords erlaubt sind
  4536. ; 12. Liste der Aux-Variablen
  4537. ; 13. Liste der Initformen der Aux-Variablen
  4538. (defun analyze-lambdalist (lambdalist)
  4539.   (let ((L lambdalist) ; Rest der Lambdaliste
  4540.         (req nil)
  4541.         (optvar nil)
  4542.         (optinit nil)
  4543.         (optsvar nil)
  4544.         (rest 0)
  4545.         (keyflag nil)
  4546.         (keyword nil)
  4547.         (keyvar nil)
  4548.         (keyinit nil)
  4549.         (keysvar nil)
  4550.         (allow-other-keys nil)
  4551.         (auxvar nil)
  4552.         (auxinit nil))
  4553.        ; alle in umgedrehter Reihenfolge
  4554.     (macrolet ((err-illegal (item)
  4555.                  `(catch 'c-error
  4556.                     (c-error #+DEUTSCH "Dieser Lambdalistenmarker ist an dieser Stelle nicht erlaubt: ~S"
  4557.                              #+ENGLISH "Lambda list marker ~S not allowed here."
  4558.                              ,item
  4559.                   ) )
  4560.                )
  4561.                (err-norest ()
  4562.                  `(catch 'c-error
  4563.                     (c-error #+DEUTSCH "Fehlender &REST-Parameter in der Lambdaliste: ~S"
  4564.                              #+ENGLISH "Missing &REST parameter in lambda list ~S"
  4565.                              lambdalist
  4566.                   ) )
  4567.                )
  4568.                (err-superflu (item)
  4569.                  `(catch 'c-error
  4570.                     (c-error #+DEUTSCH "Überflüssiges Lambdalisten-Element: ~S"
  4571.                              #+ENGLISH "Lambda list element ~S is superfluous."
  4572.                              ,item
  4573.                   ) )
  4574.               ))
  4575.       ; Required Parameter:
  4576.       (loop
  4577.         (if (atom L) (return))
  4578.         (let ((item (car L)))
  4579.           (if (symbolp item)
  4580.             (if (memq item lambda-list-keywords)
  4581.               (if (memq item '(&optional &rest &key &aux))
  4582.                 (return)
  4583.                 (err-illegal item)
  4584.               )
  4585.               (push item req)
  4586.             )
  4587.             (lambdalist-error item)
  4588.         ) )
  4589.         (setq L (cdr L))
  4590.       )
  4591.       ; Hier gilt (or (atom L) (member (car L) '(&optional &rest &key &aux))).
  4592.       ; Optionale Parameter:
  4593.       (when (and (consp L) (eq (car L) '&optional))
  4594.         (setq L (cdr L))
  4595.         (loop
  4596.           (if (atom L) (return))
  4597.           (let ((item (car L)))
  4598.             (if (symbolp item)
  4599.               (if (memq item lambda-list-keywords)
  4600.                 (if (memq item '(&rest &key &aux))
  4601.                   (return)
  4602.                   (err-illegal item)
  4603.                 )
  4604.                 (progn (push item optvar) (push nil optinit) (push 0 optsvar))
  4605.               )
  4606.               (if (and (consp item) (symbolp (car item)))
  4607.                 (if (null (cdr item))
  4608.                   (progn (push (car item) optvar) (push nil optinit) (push 0 optsvar))
  4609.                   (if (consp (cdr item))
  4610.                     (if (null (cddr item))
  4611.                       (progn (push (car item) optvar) (push (cadr item) optinit) (push 0 optsvar))
  4612.                       (if (and (consp (cddr item)) (symbolp (caddr item)) (null (cdddr item)))
  4613.                         (progn (push (car item) optvar) (push (cadr item) optinit) (push (caddr item) optsvar))
  4614.                         (lambdalist-error item)
  4615.                     ) )
  4616.                     (lambdalist-error item)
  4617.                 ) )
  4618.                 (lambdalist-error item)
  4619.           ) ) )
  4620.           (setq L (cdr L))
  4621.       ) )
  4622.       ; Hier gilt (or (atom L) (member (car L) '(&rest &key &aux))).
  4623.       ; Rest-Parameter:
  4624.       (when (and (consp L) (eq (car L) '&rest))
  4625.         (setq L (cdr L))
  4626.         (if (atom L)
  4627.           (err-norest)
  4628.           (prog ((item (car L)))
  4629.             (if (symbolp item)
  4630.               (if (memq item lambda-list-keywords)
  4631.                 (progn (err-norest) (return))
  4632.                 (setq rest item)
  4633.               )
  4634.               (lambdalist-error item)
  4635.             )
  4636.             (setq L (cdr L))
  4637.       ) ) )
  4638.       ; Vorrücken bis zum nächsten &key oder &aux :
  4639.       (loop
  4640.         (when (atom L) (return))
  4641.         (let ((item (car L)))
  4642.           (if (memq item lambda-list-keywords)
  4643.             (if (memq item '(&key &aux))
  4644.               (return)
  4645.               (err-illegal item)
  4646.             )
  4647.             (err-superflu item)
  4648.         ) )
  4649.         (setq L (cdr L))
  4650.       )
  4651.       ; Hier gilt (or (atom L) (member (car L) '(&key &aux))).
  4652.       ; Keyword-Parameter:
  4653.       (when (and (consp L) (eq (car L) '&key))
  4654.         (setq L (cdr L))
  4655.         (setq keyflag t)
  4656.         (loop
  4657.           (if (atom L) (return))
  4658.           (let ((item (car L)))
  4659.             (if (symbolp item)
  4660.               (if (memq item lambda-list-keywords)
  4661.                 (if (memq item '(&allow-other-keys &aux))
  4662.                   (return)
  4663.                   (err-illegal item)
  4664.                 )
  4665.                 (progn
  4666.                   (push (intern (symbol-name item) *keyword-package*) keyword)
  4667.                   (push item keyvar) (push nil keyinit) (push 0 keysvar)
  4668.               ) )
  4669.               (if (and
  4670.                     (consp item)
  4671.                     (or
  4672.                       (symbolp (car item))
  4673.                       (and (consp (car item))
  4674.                            (keywordp (caar item))
  4675.                            (consp (cdar item))
  4676.                            (symbolp (cadar item))
  4677.                            (null (cddar item))
  4678.                     ) )
  4679.                     (or (null (cdr item))
  4680.                         (and (consp (cdr item))
  4681.                              (or (null (cddr item))
  4682.                                  (and (consp (cddr item)) (symbolp (caddr item)) (null (cdddr item)))
  4683.                   ) )   )    )
  4684.                 (progn
  4685.                   (if (consp (car item))
  4686.                     (progn (push (caar item) keyword) (push (cadar item) keyvar))
  4687.                     (progn (push (intern (symbol-name (car item)) *keyword-package*) keyword) (push (car item) keyvar))
  4688.                   )
  4689.                   (if (consp (cdr item))
  4690.                     (progn
  4691.                       (push (cadr item) keyinit)
  4692.                       (if (consp (cddr item))
  4693.                         (push (caddr item) keysvar)
  4694.                         (push 0 keysvar)
  4695.                     ) )
  4696.                     (progn (push nil keyinit) (push 0 keysvar))
  4697.                 ) )
  4698.                 (lambdalist-error item)
  4699.           ) ) )
  4700.           (setq L (cdr L))
  4701.         )
  4702.         ; Hier gilt (or (atom L) (member (car L) '(&allow-other-keys &aux))).
  4703.         (when (and (consp L) (eq (car L) '&allow-other-keys))
  4704.           (setq allow-other-keys t)
  4705.           (setq L (cdr L))
  4706.       ) )
  4707.       ; Vorrücken bis zum nächsten &AUX :
  4708.       (loop
  4709.         (when (atom L) (return))
  4710.         (let ((item (car L)))
  4711.           (if (memq item lambda-list-keywords)
  4712.             (if (memq item '(&aux))
  4713.               (return)
  4714.               (err-illegal item)
  4715.             )
  4716.             (err-superflu item)
  4717.         ) )
  4718.         (setq L (cdr L))
  4719.       )
  4720.       ; Hier gilt (or (atom L) (member (car L) '(&aux))).
  4721.       ; &AUX-Variablen:
  4722.       (when (and (consp L) (eq (car L) '&aux))
  4723.         (setq L (cdr L))
  4724.         (loop
  4725.           (if (atom L) (return))
  4726.           (let ((item (car L)))
  4727.             (if (symbolp item)
  4728.               (if (memq item lambda-list-keywords)
  4729.                 (err-illegal item)
  4730.                 (progn (push item auxvar) (push nil auxinit))
  4731.               )
  4732.               (if (and (consp item) (symbolp (car item)))
  4733.                 (if (null (cdr item))
  4734.                   (progn (push (car item) auxvar) (push nil auxinit))
  4735.                   (if (and (consp (cdr item)) (null (cddr item)))
  4736.                     (progn (push (car item) auxvar) (push (cadr item) auxinit))
  4737.                     (lambdalist-error item)
  4738.                 ) )
  4739.                 (lambdalist-error item)
  4740.           ) ) )
  4741.           (setq L (cdr L))
  4742.       ) )
  4743.       ; Hier gilt (atom L).
  4744.       (if L
  4745.         (catch 'c-error
  4746.           (c-error #+DEUTSCH "Eine Lambdaliste, die einen Punkt enthält, ist nur bei Macros erlaubt, nicht hier: ~S"
  4747.                    #+ENGLISH "Lambda lists with dots are only allowed in macros, not here: ~S"
  4748.                    lambdalist
  4749.       ) ) )
  4750.     )
  4751.     (values
  4752.       (nreverse req)
  4753.       (nreverse optvar) (nreverse optinit) (nreverse optsvar)
  4754.       rest
  4755.       keyflag
  4756.       (nreverse keyword) (nreverse keyvar) (nreverse keyinit) (nreverse keysvar)
  4757.       allow-other-keys
  4758.       (nreverse auxvar) (nreverse auxinit)
  4759. ) ) )
  4760.  
  4761. (defun lambdalist-error (item)
  4762.   (catch 'c-error
  4763.     (c-error #+DEUTSCH "Unzulässiges Lambdalistenelement: ~S"
  4764.              #+ENGLISH "Illegal lambda list element ~S"
  4765.              item
  4766. ) ) )
  4767.  
  4768. ; (inline-callable-function-p form n) stellt fest, ob form eine Form ist, die
  4769. ; eine Funktion liefert, die mit n (und evtl. mehr) Argumenten Inline
  4770. ; aufgerufen werden kann. (vorbehaltlich Syntax-Errors in der Lambdaliste)
  4771. (defun inline-callable-function-p (form n &optional (more nil))
  4772.   ; muß von der Bauart (FUNCTION funname) sein
  4773.   (and (consp form) (eq (first form) 'FUNCTION)
  4774.        (consp (cdr form)) (null (cddr form))
  4775.        (let ((funname (second form)))
  4776.          ; funname muß von der Bauart (LAMBDA lambdalist ...) sein
  4777.          (and (consp funname) (eq (first funname) 'LAMBDA) (consp (cdr funname))
  4778.               (let ((lambdalist (second funname)))
  4779.                 ; lambdalist muß eine Liste sein, die kein &KEY enthält
  4780.                 ; (Funktionen mit &KEY werden nicht INLINE-expandiert, weil die
  4781.                 ; Zuordnung von den Argumenten zu den Variablen nur dynamisch,
  4782.                 ; mit GETF, möglich ist, und das kann die in Assembler
  4783.                 ; geschriebene APPLY-Routine schneller.)
  4784.                 (and (listp lambdalist)
  4785.                      (not (position '&KEY lambdalist))
  4786.                      (not (position '&ALLOW-OTHER-KEYS lambdalist))
  4787.                      (let ((&opt-pos (position '&OPTIONAL lambdalist))
  4788.                            (&rest-pos (position '&REST lambdalist))
  4789.                            (&aux-pos (or (position '&AUX lambdalist)
  4790.                                          (length lambdalist)
  4791.                           ))         )
  4792.                        (if &rest-pos
  4793.                          ; &rest angegeben
  4794.                          (or more (>= n (or &opt-pos &rest-pos)))
  4795.                          ; &rest nicht angegeben
  4796.                          (if more
  4797.                            (<= n (if &opt-pos (- &aux-pos 1) &aux-pos))
  4798.                            (if &opt-pos
  4799.                              (<= &opt-pos n (- &aux-pos 1))
  4800.                              (= n &aux-pos)
  4801.                      ) ) ) )
  4802.               ) )
  4803.        ) )
  4804. ) )
  4805.  
  4806.  
  4807. ;; Special-deklarierte Symbole:
  4808.  
  4809. (defvar *specials*) ; Liste aller zuletzt special deklarierten Symbole
  4810. (defvar *ignores*) ; Liste aller zuletzt ignore deklarierten Symbole
  4811. (defvar *ignorables*) ; Liste aller zuletzt ignorable deklarierten Symbole
  4812.  
  4813. ; pusht alle Symbole von specials als Variablen auf *venv* :
  4814. (defun push-specials ()
  4815.   (apply #'push-*venv* (mapcar #'make-special-var *specials*))
  4816. )
  4817.  
  4818. ; Überprüft eine Variable, ob sie zu Recht ignore-deklariert ist oder nicht...
  4819. (defun ignore-check (var)
  4820.   (let ((sym (var-name var)))
  4821.     (if (member sym *ignores* :test #'eq)
  4822.       ; var ignore-deklariert
  4823.       (if (var-specialp var)
  4824.         (c-warn #+DEUTSCH "Binden der Variablen ~S kann trotz IGNORE-Deklaration~%Seiteneffekte haben, weil sie SPECIAL deklariert ist."
  4825.                 #+ENGLISH "Binding variable ~S can cause side effects despite of IGNORE declaration~%since it is declared SPECIAL."
  4826.                 sym
  4827.         )
  4828.         (if (var-usedp var)
  4829.           (c-warn #+DEUTSCH "Variable ~S wird trotz IGNORE-Deklaration benutzt."
  4830.                   #+ENGLISH "variable ~S is used despite of IGNORE declaration."
  4831.                   sym
  4832.       ) ) )
  4833.       ; var nicht ignore-deklariert
  4834.       (unless (member sym *ignorables* :test #'eq)
  4835.         ; var auch nicht ignorable-deklariert
  4836.         (unless (or (var-specialp var) (var-usedp var))
  4837.           ; var lexikalisch und unbenutzt
  4838.           (unless (null (symbol-package sym)) ; sym ein (gensym) ?
  4839.             ; (Symbole ohne Home-Package kommen nicht vom Benutzer, die Warnung
  4840.             ; würde nur verwirren).
  4841.             (c-warn #+DEUTSCH "Variable ~S wird nicht benutzt.~%Schreibfehler oder fehlende IGNORE-Deklaration?"
  4842.                     #+ENGLISH "variable ~S is not used.~%Misspelled or missing IGNORE declaration?"
  4843.                     sym
  4844. ) ) ) ) ) ) )
  4845.  
  4846. ; liefert den Code, der zum neuen Aufbau einer Closure und ihrer Unterbringung
  4847. ; im Stack nötig ist:
  4848. ; Dieser Code erweitert das von (cdr venvc) beschriebene Venv um closurevars,
  4849. ; (cdr stackz) ist der aktuelle Stackzustand.
  4850. ; Nach Aufbau der Closure sind venvc bzw. stackz die aktuellen Zustände.
  4851. (defun c-MAKE-CLOSURE (closurevars venvc stackz)
  4852.   (if closurevars
  4853.     `((VENV ,(cdr venvc) ,(cdr stackz))
  4854.       (MAKE-VECTOR1&PUSH ,(length closurevars))
  4855.      )
  4856.     '()
  4857. ) )
  4858.  
  4859. ;; Es gibt zwei Arten von Variablen-Bindungs-Vorgehensweisen:
  4860. ; 1. fixed-var: die Variable hat eine Position im Stack, darf nicht wegoptimiert
  4861. ;               werden. Ist die Variable dann doch in der Closure, so muß ihr
  4862. ;               Wert dorthin übertragen werden; ist die Variable dynamisch, so
  4863. ;               muß ein Bindungsframe aufgemacht werden.
  4864. ;               Auftreten: MULTIPLE-VALUE-BIND, Lambda-Ausdruck (required,
  4865. ;               optional, rest, keyword - Parameter)
  4866. ; 2. movable-var: die Variable darf wegoptimiert werden, falls sie konstant ist
  4867. ;                 (sie entweder dynamisch und konstant ist oder lexikalisch
  4868. ;                  und an eine Konstante gebunden und nie geSETQed wird). Hier
  4869. ;                 spielt also der Init-Wert eine Rolle.
  4870. ;                 Auftreten: LET, LET*, Lambda-Ausdruck (optional-svar,
  4871. ;                 keyword-svar, aux-Variablen)
  4872.  
  4873. ;; 1. fixed-var
  4874.  
  4875. ; Bindung einer fixed-var:
  4876. ; symbol --> Variable
  4877. ; Läßt *stackz* unverändert.
  4878. (defun bind-fixed-var-1 (symbol)
  4879.   (if (or (constantp symbol)
  4880.           (proclaimed-special-p symbol)
  4881.           (member symbol *specials* :test #'eq)
  4882.       )
  4883.     ; muß symbol dynamisch binden:
  4884.     (progn
  4885.       (when (c-constantp symbol)
  4886.         (catch 'c-error
  4887.           (c-error #+DEUTSCH "Konstante ~S kann nicht gebunden werden."
  4888.                    #+ENGLISH "Constant ~S cannot be bound."
  4889.                    symbol
  4890.       ) ) )
  4891.       (make-special-var symbol)
  4892.     )
  4893.     ; muß symbol lexikalisch binden:
  4894.     (make-var :name symbol :specialp nil :constantp nil
  4895.               :usedp nil :really-usedp nil :closurep nil
  4896.               :stackz *stackz* :venvc *venvc*
  4897.     )
  4898. ) )
  4899.  
  4900. ; registriert in *stackz*, daß eine fixed-var gebunden wird
  4901. (defun bind-fixed-var-2 (var)
  4902.   (when (and (var-specialp var) (not (var-constantp var)))
  4903.     (push '(BIND 1) *stackz*)
  4904. ) )
  4905.  
  4906. ; liefert den Code, der die Variable var an den Inhalt von stackdummyvar
  4907. ; bindet. stackz ist der Stackzustand vor dem Binden dieser Variablen.
  4908. (defun c-bind-fixed-var (var stackdummyvar stackz)
  4909.   (if (var-specialp var)
  4910.     (if (var-constantp var)
  4911.       '() ; Konstante kann nicht gebunden werden
  4912.       `((GET ,stackdummyvar ,*venvc* ,stackz)
  4913.         (BIND ,(new-const (var-name var)))
  4914.        )
  4915.     )
  4916.     ; var lexikalisch, nach Definition nicht konstant
  4917.     (if (var-closurep var)
  4918.       `((GET ,stackdummyvar ,*venvc* ,stackz)
  4919.         (SET ,var ,*venvc* ,stackz)
  4920.        )
  4921.       '() ; var und stackdummyvar identisch
  4922. ) ) )
  4923.  
  4924. ; Kreiert je eine Stackvariable und eine Fixed-Variable zu jedem Symbol aus der
  4925. ; Variablenliste symbols und liefert beide Listen als Werte.
  4926. (defun process-fixed-var-list (symbols &optional optimflags)
  4927.   (do ((symbolsr symbols (cdr symbolsr))
  4928.        (optimflagsr optimflags (cdr optimflagsr))
  4929.        (varlist nil) ; Liste der Variablen
  4930.        (stackvarlist nil)) ; Liste der Stackvariablen (teils Dummys)
  4931.       ((null symbolsr) (values (nreverse varlist) (nreverse stackvarlist)))
  4932.     (push 1 *stackz*)
  4933.     ; (mit constantp=nil und really-usedp=t, um eine Wegoptimierung zu vermeiden)
  4934.     (push (make-var :name (gensym) :specialp nil :constantp nil
  4935.                     :usedp nil :really-usedp (null (car optimflagsr))
  4936.                     :closurep nil :stackz *stackz* :venvc *venvc*
  4937.           )
  4938.           stackvarlist
  4939.     )
  4940.     (push (bind-fixed-var-1 (car symbolsr)) varlist)
  4941. ) )
  4942.  
  4943. ; Eliminiert alle Zuweisungen auf eine unbenutzte Variable.
  4944. (defun unmodify-unused-var (var)
  4945.   (dolist (modified (var-modified-list var))
  4946.     (let ((value-anode (car modified))) ; Anode für zugewiesenen Wert
  4947.       (when (null (cdr (anode-seclass value-anode)))
  4948.         (setf (anode-code value-anode) '()) ; evtl. Wert-Form entfernen
  4949.     ) )
  4950.     (let ((set-anode (cdr modified))) ; Anode der Zuweisung selbst
  4951.       (setf (anode-code set-anode) '()) ; Zuweisung entfernen
  4952. ) ) )
  4953.  
  4954. ; Überprüft und optimiert die Variablen
  4955. ; und liefert die Liste der Closure-Variablen (in der richtigen Reihenfolge).
  4956. (defun checking-fixed-var-list (varlist &optional optimflaglist)
  4957.   (let ((closurevarlist '()))
  4958.     (dolist (var varlist (nreverse closurevarlist))
  4959.       ; 1. Schritt: eventuelle Warnungen ausgeben
  4960.       (ignore-check var)
  4961.       ; 2. Schritt: Variablen-Ort (Stack oder Closure) endgültig bestimmen,
  4962.       ; evtl. optimieren
  4963.       (unless (var-specialp var)
  4964.         ; nur lexikalische Variablen können in der Closure liegen,
  4965.         ; nur bei lexikalischen Variablen kann optimiert werden
  4966.         (if (not (var-really-usedp var))
  4967.           ; Variable lexikalisch und unbenutzt
  4968.           (progn ; Variable eliminieren
  4969.             (setf (var-closurep var) nil)
  4970.             (when (car optimflaglist) ; optimierbare fixed-var?
  4971.               (setf (first (var-stackz var)) 0) ; aus dem Stack entfernen
  4972.               (setf (car optimflaglist) 'GONE) ; als gestrichen vermerken
  4973.             )
  4974.             (unmodify-unused-var var) ; Zuweisungen auf var eliminieren
  4975.           )
  4976.           (when (var-closurep var)
  4977.             ; Variable muß in der Closure liegen
  4978.             (push var closurevarlist)
  4979.       ) ) )
  4980.       (setq optimflaglist (cdr optimflaglist))
  4981. ) ) )
  4982.  
  4983. ;; 2. movable-var
  4984.  
  4985. ; Beim Binden einer Variablen var an einen Anode anode:
  4986. ; Wird eine lexikalische Variable an den Wert an einer lexikalischen Variablen
  4987. ; gebunden? Wenn ja, an welche Variable?
  4988. (defun bound-to-var-p (var anode)
  4989.   (if (var-specialp var)
  4990.     nil
  4991.     ; var lexikalisch
  4992.     (loop
  4993.       (unless (eql (length (anode-code anode)) 1) (return nil))
  4994.       (setq anode (first (anode-code anode)))
  4995.       (unless (anode-p anode)
  4996.         (if (and (consp anode) (eq (first anode) 'GET))
  4997.           ; Code zum Anode besteht genau aus ((GET outervar ...)).
  4998.           (return (second anode))
  4999.           (return nil)
  5000.     ) ) )
  5001. ) )
  5002.  
  5003. ; Bindung einer movable-var:
  5004. ; symbol form-anode --> Variable
  5005. ; erweitert *stackz* um genau einen Eintrag
  5006. (defun bind-movable-var (symbol form-anode)
  5007.   (if (or (constantp symbol)
  5008.           (proclaimed-special-p symbol)
  5009.           (member symbol *specials* :test #'eq)
  5010.       )
  5011.     ; muß symbol dynamisch binden:
  5012.     (progn
  5013.       (if (c-constantp symbol)
  5014.         (progn
  5015.           (catch 'c-error
  5016.             (c-error #+DEUTSCH "Konstante ~S kann nicht gebunden werden."
  5017.                      #+ENGLISH "Constant ~S cannot be bound."
  5018.                      symbol
  5019.           ) )
  5020.           (push 0 *stackz*)
  5021.         )
  5022.         (push '(BIND 1) *stackz*)
  5023.       )
  5024.       (make-special-var symbol)
  5025.     )
  5026.     ; muß symbol lexikalisch binden:
  5027.     (let ((var
  5028.             (progn
  5029.               (push 1 *stackz*) ; vorläufig: 1 Platz auf dem Stack
  5030.               (make-var :name symbol :specialp nil
  5031.                 :constantp (anode-constantp form-anode) ; wird bei Zuweisungen auf NIL gesetzt
  5032.                 :constant (if (anode-constantp form-anode) (anode-constant form-anode))
  5033.                 :usedp nil :really-usedp nil :closurep nil ; wird evtl. auf T gesetzt
  5034.                 :stackz *stackz* :venvc *venvc*
  5035.          )) ) )
  5036.       (let ((outervar (bound-to-var-p var form-anode)))
  5037.         (when outervar ; Wird var an eine Variable outervar gebunden, so
  5038.                        ; darf später evtl. jede Referenz zu var in eine
  5039.                        ; Referenz zu outervar umgewandelt werden.
  5040.           (push (list var form-anode) (var-replaceable-list outervar))
  5041.       ) )
  5042.       var
  5043. ) ) )
  5044.  
  5045. ; liefert den Code, der die Variable var an A0 bindet:
  5046. (defun c-bind-movable-var (var)
  5047.   (if (var-specialp var)
  5048.     (if (var-constantp var)
  5049.       '() ; dynamische Konstanten können nicht gebunden werden
  5050.       `((BIND ,(new-const (var-name var))))
  5051.     )
  5052.     (if (var-closurep var)
  5053.       ; Closure-Variable schreiben:
  5054.       ; (var-stackz var) = (0 . ...) ist der aktuelle Stackzustand.
  5055.       `((SET ,var ,*venvc* ,(var-stackz var)))
  5056.       ; lexikalische Variable: wurde eventuell aus dem Stack eliminiert
  5057.       (if (zerop (first (var-stackz var)))
  5058.         '()
  5059.         `((PUSH)) ; im Stack: in die nächstuntere Stacklocation schreiben
  5060. ) ) ) )
  5061.  
  5062. ; liefert den Code, der die Variable var an das Ergebnis des ANODEs anode bindet
  5063. (defun c-bind-movable-var-anode (var anode)
  5064.   (let ((binding-anode
  5065.           (make-anode :type 'BIND-MOVABLE
  5066.                       :sub-anodes '()
  5067.                       :seclass '(NIL . NIL)
  5068.                       :code (c-bind-movable-var var)
  5069.        )) )
  5070.     (let ((outervar (bound-to-var-p var anode)))
  5071.       (when outervar ; Wird var an eine Variable outervar gebunden, so
  5072.                      ; darf später evtl. jede Referenz zu var in eine
  5073.                      ; Referenz zu outervar umgewandelt werden.
  5074.         (dolist (innervar-info (var-replaceable-list outervar))
  5075.           (when (eq (first innervar-info) var)
  5076.             (setf (cddr innervar-info) binding-anode) ; binding-anode nachtragen
  5077.     ) ) ) )
  5078.     (list anode binding-anode)
  5079. ) )
  5080.  
  5081. ; (process-movable-var-list symbols initforms *-flag) compiliert die initforms
  5082. ; (wie bei LET/LET*) und assoziiert sie mit den Variablen zu symbols.
  5083. ; Verändert *venv* (bei *-flag : incrementell, sonst auf einmal).
  5084. ; Liefert drei Werte:
  5085. ; 1. Liste der Variablen,
  5086. ; 2. Liste der ANODEs zu den initforms,
  5087. ; 3. Liste der Stackzustände nach dem Binden der Variablen.
  5088. (defun process-movable-var-list (symbols initforms *-flag)
  5089.   (do ((symbolsr symbols (cdr symbolsr))
  5090.        (initformsr initforms (cdr initformsr))
  5091.        (varlist '())
  5092.        (anodelist '())
  5093.        (stackzlist '()))
  5094.       ((null symbolsr)
  5095.        (unless *-flag (apply #'push-*venv* varlist)) ; Binden bei LET
  5096.        (values (nreverse varlist) (nreverse anodelist) (nreverse stackzlist))
  5097.       )
  5098.     (let* ((initform (car initformsr))
  5099.            (anode (c-form initform 'ONE)) ; initform compilieren
  5100.            (var (bind-movable-var (car symbolsr) anode)))
  5101.       (push anode anodelist)
  5102.       (push var varlist)
  5103.       (push *stackz* stackzlist)
  5104.       (when *-flag (push-*venv* var)) ; Binden bei LET*
  5105. ) ) )
  5106.  
  5107. ; Überprüft und optimiert die Variablen (wie bei LET/LET*)
  5108. ; und liefert die Liste der Closure-Variablen (in der richtigen Reihenfolge).
  5109. (defun checking-movable-var-list (varlist anodelist)
  5110.   (do ((varlistr varlist (cdr varlistr))
  5111.        (anodelistr anodelist (cdr anodelistr))
  5112.        (closurevarlist '()))
  5113.       ((null varlistr) (nreverse closurevarlist))
  5114.     (let ((var (car varlistr)))
  5115.       (when var
  5116.         ; 1. Schritt: eventuelle Warnungen ausgeben
  5117.         (ignore-check var)
  5118.         ; 2. Schritt: Variablen-Ort (Stack oder Closure oder eliminiert)
  5119.         ; endgültig bestimmen
  5120.         (unless (var-specialp var)
  5121.           ; nur bei lexikalischen Variablen kann optimiert werden
  5122.           (if (var-constantp var)
  5123.             ; Variable lexikalisch und konstant
  5124.             (progn ; Variable eliminieren
  5125.               (setf (var-closurep var) nil)
  5126.               (setf (first (var-stackz var)) 0) ; aus dem Stack entfernen
  5127.               (when (null (cdr (anode-seclass (car anodelistr))))
  5128.                 (setf (anode-code (car anodelistr)) '()) ; evtl. initform entfernen
  5129.             ) )
  5130.             (if (not (var-really-usedp var))
  5131.               ; Variable lexikalisch und unbenutzt
  5132.               (progn ; Variable eliminieren
  5133.                 (setf (var-closurep var) nil)
  5134.                 (setf (first (var-stackz var)) 0) ; aus dem Stack entfernen
  5135.                 (when (null (cdr (anode-seclass (car anodelistr))))
  5136.                   (setf (anode-code (car anodelistr)) '()) ; evtl. initform entfernen
  5137.                 )
  5138.                 (unmodify-unused-var var) ; Zuweisungen auf var eliminieren
  5139.               )
  5140.               (when (var-closurep var)
  5141.                 ; Variable muß in der Closure liegen
  5142.                 (setf (first (var-stackz var)) 0) ; belegt 0 Stack-Einträge
  5143.                 (push var closurevarlist)
  5144.         ) ) ) )
  5145. ) ) ) )
  5146.  
  5147. ; Optimiert eine Liste von Variablen.
  5148. ; (In der Liste müssen die lexikalisch inneren Variablen zuletzt kommen.)
  5149. (defun optimize-var-list (vars)
  5150.   (unless *no-code*
  5151.     (dolist (var (reverse vars))
  5152.       (when var
  5153.         ; Optimierung (innere Variablen zuerst):
  5154.         ; Wird eine Variable innervar an den Wert von var gebunden, wird
  5155.         ; während der Lebensdauer von innervar weder innervar noch var verändert
  5156.         ; (um dies sicherstellen zu können, müssen beide lexikalisch und im Stack
  5157.         ; sein), so kann innervar durch var ersetzt werden.
  5158.         (unless (or (var-specialp var) (var-closurep var))
  5159.           ; var ist lexikalisch und im Stack
  5160.           (dolist (innervar-info (var-replaceable-list var))
  5161.             (let ((innervar (first innervar-info)))
  5162.               ; innervar ist eine movable-var, die mit var initialisiert wird.
  5163.               ; Während der Lebensdauer von innervar wird var nichts zugewiesen.
  5164.               (unless (or (var-specialp innervar) (var-closurep innervar))
  5165.                 ; innervar ist lexikalisch und im Stack
  5166.                 (when (null (var-modified-list innervar))
  5167.                   ; Während der Lebensdauer von innervar wird auch innervar
  5168.                   ; nichts zugewiesen.
  5169.                   (unless (eql (first (var-stackz innervar)) 0) ; innervar noch nicht wegoptimiert?
  5170.                     (when (cddr innervar-info) ; und innervar-info korrekt dreigliedrig?
  5171.                       ; Variable innervar eliminieren:
  5172.                       (setf (first (var-stackz innervar)) 0) ; aus dem Stack entfernen
  5173.                       ; Initialisierung und Binden von innervar eliminieren:
  5174.                       (setf (anode-code (second innervar-info)) '())
  5175.                       (setf (anode-code (cddr innervar-info)) '())
  5176.                       ; Die Referenzen auf die Variable innervar werden
  5177.                       ; in Referenzen auf die Variable var umgewandelt:
  5178.                       (let ((using-var (var-usedp var)))
  5179.                         (do ((using-innervar (var-usedp innervar) (cdr using-innervar)))
  5180.                             ((atom using-innervar))
  5181.                           (let* ((anode (car using-innervar)) ; ein Anode vom Typ VAR
  5182.                                  (code (anode-code anode))) ; sein Code, () oder ((GET ...))
  5183.                             (unless (null code)
  5184.                               ; (anode-code anode) ist von der Gestalt ((GET innervar ...))
  5185.                               (setf (second (car code)) var)
  5186.                               (push anode using-var)
  5187.                         ) ) )
  5188.                         (setf (var-usedp var) using-var)
  5189.                       )
  5190.         ) ) ) ) ) ) )
  5191. ) ) ) )
  5192.  
  5193. ; Bildet den Code, der eine Liste von Variablen, zusammen mit ihren svars,
  5194. ; bindet (wie bei Lambdabody- Optional/Key - Variablen).
  5195. (defun c-bind-with-svars (-vars -dummys s-vars -anodes s-anodes -stackzs)
  5196.   (do ((-varsr -vars (cdr -varsr)) ; fixed-vars
  5197.        (-dummysr -dummys (cdr -dummysr))
  5198.        (s-varsr s-vars (cdr s-varsr)) ; movable-vars
  5199.        (-anodesr -anodes (cdr -anodesr))
  5200.        (s-anodesr s-anodes (cdr s-anodesr))
  5201.        (-stackzsr -stackzs (cdr -stackzsr))
  5202.        (L '()))
  5203.       ((null -varsr) (nreverse L))
  5204.     (when (car s-varsr)
  5205.       (setq L
  5206.         (revappend
  5207.           (c-bind-movable-var-anode (car s-varsr) (car s-anodesr))
  5208.           L
  5209.     ) ) )
  5210.     (setq L
  5211.       (revappend
  5212.         (let* ((var (car -varsr))
  5213.                (stackdummyvar (car -dummysr))
  5214.                (anode (car -anodesr))
  5215.                (stackz (car -stackzsr))
  5216.                (label (make-label 'ONE)))
  5217.           (if (var-specialp var)
  5218.             `((JMPIFBOUNDP ,stackdummyvar ,*venvc* ,stackz ,label)
  5219.               ,anode
  5220.               ,label
  5221.               ,@(if (var-constantp var)
  5222.                   '() ; Konstante kann nicht gebunden werden
  5223.                   `((BIND ,(new-const (var-name var))))
  5224.                 )
  5225.              )
  5226.             ; var lexikalisch, nach Definition nicht konstant
  5227.             (if (var-closurep var)
  5228.               `((JMPIFBOUNDP ,stackdummyvar ,*venvc* ,stackz ,label)
  5229.                 ,anode
  5230.                 ,label
  5231.                 (SET ,var ,*venvc* ,stackz)
  5232.                )
  5233.               (if (not (var-really-usedp var))
  5234.                 ; Variable wurde in checking-fixed-var-list wegoptimiert
  5235.                 (if (cdr (anode-seclass anode))
  5236.                   `((JMPIFBOUNDP ,stackdummyvar ,*venvc* ,stackz ,label)
  5237.                     ,anode
  5238.                     ,label
  5239.                    )
  5240.                   '()
  5241.                 )
  5242.                 ; im Stack vorhandene Variable
  5243.                 `((JMPIFBOUNDP ,stackdummyvar ,*venvc* ,stackz ,label)
  5244.                   ,anode
  5245.                   (SET ,var ,*venvc* ,stackz)
  5246.                   ,label
  5247.                  )
  5248.         ) ) ) )
  5249.         L
  5250.     ) )
  5251. ) )
  5252.  
  5253. ; compiliere (name lambdalist {declaration|docstring}* {form}*), liefere FNODE
  5254. (defun c-LAMBDABODY (name lambdabody &optional fenv-cons gf-p reqoptimflags)
  5255.   (test-list lambdabody 1)
  5256.   (let* ((*func* (make-fnode :name name :enclosing *func* :venvc *venvc*))
  5257.          (*stackz* *func*) ; leerer Stack
  5258.          (*venvc* (cons *func* *venvc*))
  5259.          (*func-start-label* (make-label 'NIL))
  5260.          (*anonymous-count* 0)
  5261.          (anode (catch 'c-error
  5262.     ; ab hier wird's kompliziert
  5263.     (multiple-value-bind (reqvar  optvar optinit optsvar  restvar
  5264.                           keyflag keyword keyvar keyinit keysvar allow-other-keys
  5265.                           auxvar auxinit)
  5266.         (if fenv-cons
  5267.           (values-list (cddar fenv-cons)) ; Bei c-LABELS wurde analyze-lambdalist schon aufgerufen
  5268.           (analyze-lambdalist (car lambdabody))
  5269.         )
  5270.       (setf (fnode-req-anz *func*) (length reqvar)
  5271.             (fnode-opt-anz *func*) (length optvar)
  5272.             (fnode-rest-flag *func*) (not (eql restvar 0))
  5273.             (fnode-keyword-flag *func*) keyflag
  5274.             (fnode-keywords *func*) keyword
  5275.             (fnode-allow-other-keys-flag *func*) allow-other-keys
  5276.       )
  5277.       (when fenv-cons (setf (caar fenv-cons) *func*)) ; Fixup für c-LABELS
  5278.       (multiple-value-bind (body-rest declarations)
  5279.           (parse-body (cdr lambdabody) t (vector *venv* *fenv*))
  5280.         (let ((oldstackz *stackz*)
  5281.               (*stackz* *stackz*)
  5282.               (*denv* *denv*)
  5283.               (*venv* *venv*)
  5284.               (*venvc* *venvc*)
  5285.               *specials* *ignores* *ignorables*
  5286.               req-vars req-dummys req-stackzs
  5287.               opt-vars opt-dummys opt-anodes opts-vars opts-anodes opt-stackzs
  5288.               rest-vars rest-dummys rest-stackzs
  5289.               key-vars key-dummys key-anodes keys-vars keys-anodes key-stackzs
  5290.               aux-vars aux-anodes
  5291.               closuredummy-stackz closuredummy-venvc
  5292.              )
  5293.           (multiple-value-setq (*specials* *ignores* *ignorables*)
  5294.             (process-declarations declarations)
  5295.           )
  5296.           ; Special-Variable auf *venv* pushen:
  5297.           (push-specials)
  5298.           ; Sichtbarkeit von Closure-Dummyvar:
  5299.           (push nil *venvc*)
  5300.           (setq closuredummy-venvc *venvc*)
  5301.           ; Stack-Dummy-Variable für die reqvar,optvar,restvar,keyvar bilden:
  5302.           (multiple-value-setq (req-vars req-dummys)
  5303.             (process-fixed-var-list reqvar reqoptimflags)
  5304.           )
  5305.           (multiple-value-setq (opt-vars opt-dummys)
  5306.             (process-fixed-var-list optvar)
  5307.           )
  5308.           (multiple-value-setq (rest-vars rest-dummys)
  5309.             (if (eql restvar 0)
  5310.               (values '() '())
  5311.               (process-fixed-var-list (list restvar))
  5312.           ) )
  5313.           (multiple-value-setq (key-vars key-dummys)
  5314.             (process-fixed-var-list keyvar)
  5315.           )
  5316.           ; Platz für die Funktion selbst (unter den Argumenten):
  5317.           (push 1 *stackz*)
  5318.           ; Platz für Closure-Dummyvar:
  5319.           (push 0 *stackz*)
  5320.           (setq closuredummy-stackz *stackz*)
  5321.           ; Bindungen der required-Parameter aktivieren:
  5322.           (setq req-stackzs (bind-req-vars req-vars))
  5323.           ; Bindungen der optional-Parameter/svar aktivieren:
  5324.           (multiple-value-setq (opt-anodes opt-stackzs opts-vars opts-anodes)
  5325.             (bind-opt-vars opt-vars opt-dummys optinit optsvar)
  5326.           )
  5327.           ; Bindung des rest-Parameters aktivieren:
  5328.           (unless (eql restvar 0)
  5329.             (setq rest-stackzs (bind-rest-vars rest-vars))
  5330.           )
  5331.           ; Bindungen der keyword-Parameter/svar aktivieren:
  5332.           (multiple-value-setq (key-anodes key-stackzs keys-vars keys-anodes)
  5333.             (bind-opt-vars key-vars key-dummys keyinit keysvar)
  5334.           )
  5335.           ; Bindungen der Aux-Variablen aktivieren:
  5336.           (multiple-value-setq (aux-vars aux-anodes)
  5337.             (bind-aux-vars auxvar auxinit)
  5338.           )
  5339.           (let* ((body-anode (c-form `(PROGN ,@body-rest) 'ALL))
  5340.                  ; Überprüfen der Variablen:
  5341.                  (closurevars
  5342.                    (append
  5343.                      (checking-fixed-var-list req-vars reqoptimflags)
  5344.                      (checking-fixed-var-list opt-vars)
  5345.                      (checking-movable-var-list opts-vars opts-anodes)
  5346.                      (checking-fixed-var-list rest-vars)
  5347.                      (checking-fixed-var-list key-vars)
  5348.                      (checking-movable-var-list keys-vars keys-anodes)
  5349.                      (checking-movable-var-list aux-vars aux-anodes)
  5350.                  ) )
  5351.                  (codelist
  5352.                    `(,*func-start-label*
  5353.                      ,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  5354.                      ,@(mapcap #'c-bind-fixed-var req-vars req-dummys req-stackzs)
  5355.                      ,@(c-bind-with-svars opt-vars opt-dummys opts-vars opt-anodes opts-anodes opt-stackzs)
  5356.                      ,@(mapcap #'c-bind-fixed-var rest-vars rest-dummys rest-stackzs)
  5357.                      ,@(c-bind-with-svars key-vars key-dummys keys-vars key-anodes keys-anodes key-stackzs)
  5358.                      ,@(mapcap #'c-bind-movable-var-anode aux-vars aux-anodes)
  5359.                      ,body-anode
  5360.                      (UNWIND ,*stackz* ,oldstackz t)
  5361.                      (RET)
  5362.                  )  )
  5363.                  (anode
  5364.                    (make-anode
  5365.                      :type 'LAMBDABODY
  5366.                      :source lambdabody
  5367.                      :sub-anodes `(,@opt-anodes ,@(remove nil opts-anodes)
  5368.                                    ,@key-anodes ,@(remove nil keys-anodes)
  5369.                                    ,@aux-anodes ,body-anode
  5370.                                   )
  5371.                      :seclass '(T . T) ; die Seiteneffektklasse dieses Anode ist irrelevant
  5372.                      :stackz oldstackz
  5373.                      :code codelist
  5374.                 )) )
  5375.             (when closurevars
  5376.               (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  5377.               (setf (first closuredummy-venvc)
  5378.                 (cons closurevars closuredummy-stackz)
  5379.             ) )
  5380.             (optimize-var-list (append req-vars opt-vars opts-vars rest-vars key-vars keys-vars aux-vars))
  5381.             anode
  5382.     ) ) ) )
  5383.     ; das war die Produktion des Anode
  5384.         ))      )
  5385.     (setf (fnode-code *func*) anode)
  5386.     (when reqoptimflags (decf (fnode-req-anz *func*) (count 'GONE reqoptimflags)))
  5387.     (when (eq (anode-type anode) 'ERROR)
  5388.       ; korrekte, aber nichtstuende Funktion daraus machen
  5389.       (setf (fnode-req-anz *func*) 0
  5390.             (fnode-opt-anz *func*) 0
  5391.             (fnode-rest-flag *func*) t
  5392.             (fnode-keyword-flag *func*) nil
  5393.             (fnode-keywords *func*) '()
  5394.             (fnode-allow-other-keys-flag *func*) nil
  5395.             (anode-code (fnode-code *func*)) `((NIL) (SKIP 2) (RET))
  5396.     ) )
  5397.     (setf (fnode-gf-p *func*) gf-p)
  5398.     (setf (fnode-Consts-Offset *func*)
  5399.       (+ (setf (fnode-Keyword-Offset *func*)
  5400.            (+ (setf (fnode-Tagbodys-Offset *func*)
  5401.                 (+ (setf (fnode-Blocks-Offset *func*)
  5402.                      (if (fnode-venvconst *func*) 1 0)
  5403.                    )
  5404.                    (length (fnode-Blocks *func*))
  5405.               ) )
  5406.               (length (fnode-Tagbodys *func*))
  5407.          ) )
  5408.          (length (fnode-Keywords *func*))
  5409.     ) )
  5410.     (when gf-p
  5411.       ; Der Dispatch generischer Funktionen kann nicht auf externe Blocks und
  5412.       ; Tagbodys verweisen. Die Keywords allerdings werden notgedrungen verlagert.
  5413.       (when (or (fnode-Blocks *func*) (fnode-Tagbodys *func*))
  5414.         (compiler-error 'c-LAMBDABODY "GF")
  5415.       )
  5416.       ; Nun ist (fnode-Keyword-Offset *func*) = (fnode-Tagbodys-Offset *func*) =
  5417.       ;       = (fnode-Blocks-Offset *func*) = (if (fnode-venvconst *func*) 1 0)
  5418.     )
  5419.     *func*
  5420. ) )
  5421. (defun bind-req-vars (req-vars)
  5422.   (let ((req-stackzs '()))
  5423.     (dolist (var req-vars)
  5424.       (push-*venv* var)
  5425.       (push *stackz* req-stackzs)
  5426.       (bind-fixed-var-2 var)
  5427.     )
  5428.     (nreverse req-stackzs)
  5429. ) )
  5430. (defun bind-opt-vars (opt-vars opt-dummys optinit optsvar)
  5431.   (let ((opt-anodes '())
  5432.         (opt-stackzs '())
  5433.         (opts-vars '())
  5434.         (opts-anodes '()))
  5435.     (do ((opt-varsr opt-vars (cdr opt-varsr))
  5436.          (opt-dummysr opt-dummys (cdr opt-dummysr))
  5437.          (optinitr optinit (cdr optinitr))
  5438.          (optsvarr optsvar (cdr optsvarr)))
  5439.         ((null opt-varsr))
  5440.       (if (eql (car optsvarr) 0)
  5441.         (progn (push nil opts-vars) (push nil opts-anodes))
  5442.         (let* ((anode
  5443.                  (make-anode
  5444.                    :type 'OPTIONAL-SVAR
  5445.                    :sub-anodes '()
  5446.                    :seclass (cons (list (car opt-dummysr)) 'NIL)
  5447.                    :code `((BOUNDP ,(car opt-dummysr) ,*venvc* ,*stackz*))
  5448.                ) )
  5449.                (var (bind-movable-var (car optsvarr) anode))
  5450.               )
  5451.           (push anode opts-anodes)
  5452.           (push var opts-vars)
  5453.       ) )
  5454.       (push (c-form (car optinitr) 'ONE) opt-anodes)
  5455.       (push-*venv* (car opt-varsr))
  5456.       (push *stackz* opt-stackzs) (bind-fixed-var-2 (car opt-varsr))
  5457.       (unless (eql (car optsvarr) 0) (push-*venv* (car opts-vars)))
  5458.     )
  5459.     (values
  5460.       (nreverse opt-anodes) (nreverse opt-stackzs)
  5461.       (nreverse opts-vars) (nreverse opts-anodes)
  5462.     )
  5463. ) )
  5464. (defun bind-rest-vars (rest-vars)
  5465.   (let ((rest-stackzs '()))
  5466.     (push-*venv* (car rest-vars))
  5467.     (push *stackz* rest-stackzs)
  5468.     (bind-fixed-var-2 (car rest-vars))
  5469.     rest-stackzs ; (nreverse rest-stackzs) unnötig
  5470. ) )
  5471. (defun bind-aux-vars (auxvar auxinit)
  5472.   (let ((aux-vars '())
  5473.         (aux-anodes '()))
  5474.     (do ((auxvarr auxvar (cdr auxvarr))
  5475.          (auxinitr auxinit (cdr auxinitr)))
  5476.         ((null auxvarr))
  5477.       (let* ((initform (car auxinitr))
  5478.              (anode (c-form initform 'ONE))
  5479.              (var (bind-movable-var (car auxvarr) anode)))
  5480.         (push anode aux-anodes)
  5481.         (push var aux-vars)
  5482.         (push-*venv* var)
  5483.     ) )
  5484.     (values (nreverse aux-vars) (nreverse aux-anodes))
  5485. ) )
  5486.  
  5487. ; liefert den ANODE, der (bei gegebenem aktuellem Stackzustand)
  5488. ; die zu einem FNODE gehörende Funktion als Wert liefert.
  5489. (defun c-FNODE-FUNCTION (fnode &optional (*stackz* *stackz*))
  5490.   (make-anode
  5491.     :type 'FUNCTION
  5492.     :sub-anodes '()
  5493.     :seclass '(NIL . NIL)
  5494.     :code (if (zerop (fnode-keyword-offset fnode))
  5495.             `((FCONST ,fnode))
  5496.             `(,@(if (fnode-Venvconst fnode)
  5497.                   (prog1 ; beim Aufbau mitzugebendes Venv
  5498.                     `((VENV ,(fnode-venvc fnode) ,*stackz*)
  5499.                       (PUSH)
  5500.                      )
  5501.                     (setq *stackz* (cons 1 *stackz*))
  5502.                 ) )
  5503.               ,@(mapcap ; beim Aufbau mitzugebende Block-Conses
  5504.                   #'(lambda (block)
  5505.                       (prog1
  5506.                         `(,(if (member block (fnode-Blocks *func*) :test #'eq)
  5507.                              `(BCONST ,block)
  5508.                              `(GET ,(block-consvar block) ,*venvc* ,*stackz*)
  5509.                            )
  5510.                            (PUSH)
  5511.                          )
  5512.                         (setq *stackz* (cons 1 *stackz*))
  5513.                     ) )
  5514.                   (fnode-Blocks fnode)
  5515.                 )
  5516.               ,@(mapcap ; beim Aufbau mitzugebende Tagbody-Conses
  5517.                   #'(lambda (tagbody)
  5518.                       (prog1
  5519.                         `(,(if (member tagbody (fnode-Tagbodys *func*) :test #'eq)
  5520.                              `(GCONST ,tagbody)
  5521.                              `(GET ,(tagbody-consvar tagbody) ,*venvc* ,*stackz*)
  5522.                            )
  5523.                            (PUSH)
  5524.                          )
  5525.                         (setq *stackz* (cons 1 *stackz*))
  5526.                     ) )
  5527.                   (fnode-Tagbodys fnode)
  5528.                 )
  5529.               (COPY-CLOSURE ,fnode ,(fnode-keyword-offset fnode))
  5530.              )
  5531.           )
  5532. ) )
  5533.  
  5534.  
  5535. ;        ERSTER PASS :   S P E C I A L   F O R M S
  5536.  
  5537. ; compiliere (PROGN {form}*)
  5538. ; keine Formen -> NIL, genau eine Form -> diese Form,
  5539. ; mindestens zwei Formen -> alle der Reihe nach, nur bei der letzten kommt es
  5540. ; auf die Werte an.
  5541. (defun c-PROGN ()
  5542.   (test-list *form* 1)
  5543.   (let ((L (cdr *form*))) ; Liste der Formen
  5544.     (cond ((null L) (c-NIL)) ; keine Form -> NIL
  5545.           ((null (cdr L)) (c-form (car L))) ; genau eine Form
  5546.           (t (do (#+COMPILER-DEBUG (anodelist '())
  5547.                   (seclass '(NIL . NIL))
  5548.                   (codelist '())
  5549.                   (Lr L)) ; restliche Formenliste
  5550.                  ((null Lr)
  5551.                   (make-anode
  5552.                     :type 'PROGN
  5553.                     :sub-anodes (nreverse anodelist)
  5554.                     :seclass seclass
  5555.                     :code (nreverse codelist)
  5556.                  ))
  5557.                (let* ((formi (pop Lr)) ; i-te Form
  5558.                       (anodei (c-form formi (if (null Lr) *for-value* 'NIL))))
  5559.                  #+COMPILER-DEBUG (push anodei anodelist)
  5560.                  (seclass-or-f seclass anodei)
  5561.                  (push anodei codelist)
  5562. ) ) )     )  ) )
  5563.  
  5564. ; compiliere (PROG1 form1 {form}*)
  5565. ; bei *for-value* muß der Wert von form1 im Stack gerettet werden
  5566. (defun c-PROG1 ()
  5567.   (test-list *form* 2)
  5568.   (if (or (null *for-value*) (and (eq *for-value* 'ONE) (null (cddr *form*))))
  5569.     (c-form `(PROGN ,@(cdr *form*)))
  5570.     (let ((anode1 (c-form (second *form*) 'ONE))
  5571.           (anode2 (let ((*stackz* (cons 1 *stackz*)))
  5572.                     (c-form `(PROGN ,@(cddr *form*)) 'NIL)
  5573.          ))       )
  5574.       (make-anode
  5575.         :type 'PROG1
  5576.         :sub-anodes (list anode1 anode2)
  5577.         :seclass (anodes-seclass-or anode1 anode2)
  5578.         :code `(,anode1 (PUSH) ,anode2 (POP))
  5579. ) ) ) )
  5580.  
  5581. ; compiliere (PROG2 form1 form2 {form}*)
  5582. (defun c-PROG2 ()
  5583.   (test-list *form* 3)
  5584.   (c-form `(PROGN ,(second *form*) (PROG1 ,(third *form*) ,@(cdddr *form*))))
  5585. )
  5586.  
  5587. ; compiliere (IF form1 form2 [form3])
  5588. ; ist form1 eine Konstante, so kann der Compiler die Fallunterscheidung treffen.
  5589. (defun c-IF ()
  5590.   (test-list *form* 3 4)
  5591.   (let ((form1 (second *form*))
  5592.         (form2 (third *form*))
  5593.         (form3 (fourth *form*))) ; = NIL, falls *form* nur 3 lang ist
  5594.     (let ((anode1 (c-form form1 'ONE)))
  5595.       (if (anode-constantp anode1)
  5596.         (if (anode-constant-value anode1)
  5597.           (prog1 (c-form form2) (let ((*no-code* t)) (c-form form3 'NIL)))
  5598.           (prog2 (let ((*no-code* t)) (c-form form2 'NIL)) (c-form form3))
  5599.         )
  5600.         (let ((anode2 (c-form form2))
  5601.               (anode3 (c-form form3))
  5602.               (label1 (make-label 'NIL))
  5603.               (label2 (make-label *for-value*)))
  5604.           (make-anode
  5605.             :type 'IF
  5606.             :sub-anodes (list anode1 anode2 anode3)
  5607.             :seclass (anodes-seclass-or anode1 anode2 anode3)
  5608.             :code
  5609.               `(,anode1
  5610.                 (JMPIFNOT ,label1)
  5611.                 ,anode2
  5612.                 (JMP ,label2)
  5613.                 ,label1
  5614.                 ,anode3
  5615.                 ,label2
  5616.                )
  5617. ) ) ) ) ) )
  5618.  
  5619. ; compiliere (WHEN form1 {form}*)
  5620. (defun c-WHEN ()
  5621.   (test-list *form* 2)
  5622.   (c-form `(IF ,(second *form*) (PROGN ,@(cddr *form*))))
  5623. )
  5624.  
  5625. ; compiliere (UNLESS form1 {form}*)
  5626. (defun c-UNLESS ()
  5627.   (test-list *form* 2)
  5628.   (c-form `(IF ,(second *form*) NIL (PROGN ,@(cddr *form*))))
  5629. )
  5630.  
  5631. ; compiliere (AND {form}*)
  5632. (defun c-AND ()
  5633.   (test-list *form* 1)
  5634.   (cond ((null (cdr *form*)) ; keine Formen
  5635.          (make-anode
  5636.            :type 'AND
  5637.            :sub-anodes '()
  5638.            :seclass '(NIL . NIL)
  5639.            :code '((T))
  5640.         ))
  5641.         ((null (cddr *form*)) (c-form (second *form*))) ; genau eine Form
  5642.         (t (do (#+COMPILER-DEBUG (anodelist '())
  5643.                 (seclass '(NIL . NIL))
  5644.                 (codelist '())
  5645.                 (Lr (cdr *form*))
  5646.                 (label (make-label *for-value*))) ; Label am Ende
  5647.                ((null Lr)
  5648.                 (push label codelist)
  5649.                 (make-anode
  5650.                   :type 'AND
  5651.                   :sub-anodes (nreverse anodelist)
  5652.                   :seclass seclass
  5653.                   :code (nreverse codelist)
  5654.                ))
  5655.              (let* ((formi (pop Lr))
  5656.                     (anodei (c-form formi (if (null Lr) *for-value* 'ONE))))
  5657.                #+COMPILER-DEBUG (push anodei anodelist)
  5658.                (seclass-or-f seclass anodei)
  5659.                (if (null Lr)
  5660.                  ; letzte Form -> direkt übernehmen
  5661.                  (push anodei codelist)
  5662.                  ; nicht letzte Form -> Test kreieren
  5663.                  (if (anode-constantp anodei)
  5664.                    ; Konstante /= NIL -> weglassen, Konstante NIL -> fertig
  5665.                    (unless (anode-constant-value anodei)
  5666.                      (if *for-value* (push '(NIL) codelist))
  5667.                      (let ((*no-code* t)) (dolist (form Lr) (c-form form 'NIL)))
  5668.                      (setq Lr nil)
  5669.                    )
  5670.                    (progn ; normaler Test
  5671.                      (push anodei codelist)
  5672.                      (push `(,(if *for-value* 'JMPIFNOT1 'JMPIFNOT) ,label)
  5673.                            codelist
  5674.              ) ) ) ) )
  5675. ) )     )  )
  5676.  
  5677. ; compiliere (OR {form}*)
  5678. (defun c-OR ()
  5679.   (test-list *form* 1)
  5680.   (cond ((null (cdr *form*)) ; keine Formen
  5681.          (make-anode
  5682.            :type 'OR
  5683.            :sub-anodes '()
  5684.            :seclass '(NIL . NIL)
  5685.            :code '((NIL))
  5686.         ))
  5687.         ((null (cddr *form*)) (c-form (second *form*))) ; genau eine Form
  5688.         (t (do (#+COMPILER-DEBUG (anodelist '())
  5689.                 (seclass '(NIL . NIL))
  5690.                 (codelist '())
  5691.                 (Lr (cdr *form*))
  5692.                 (label (make-label *for-value*))) ; Label am Ende
  5693.                ((null Lr)
  5694.                 (push label codelist)
  5695.                 (make-anode
  5696.                   :type 'OR
  5697.                   :sub-anodes (nreverse anodelist)
  5698.                   :seclass seclass
  5699.                   :code (nreverse codelist)
  5700.                ))
  5701.              (let* ((formi (pop Lr))
  5702.                     (anodei (c-form formi (if (null Lr) *for-value* 'ONE))))
  5703.                #+COMPILER-DEBUG (push anodei anodelist)
  5704.                (seclass-or-f seclass anodei)
  5705.                (if (null Lr)
  5706.                  ; letzte Form -> direkt übernehmen
  5707.                  (push anodei codelist)
  5708.                  ; nicht letzte Form -> Test kreieren
  5709.                  (if (anode-constantp anodei)
  5710.                    ; Konstante NIL -> weglassen, Konstante /= NIL -> fertig
  5711.                    (when (anode-constant-value anodei)
  5712.                      (if *for-value* (push anodei codelist))
  5713.                      (let ((*no-code* t)) (dolist (form Lr) (c-form form 'NIL)))
  5714.                      (setq Lr nil)
  5715.                    )
  5716.                    (progn ; normaler Test
  5717.                      (push anodei codelist)
  5718.                      (push `(,(if *for-value* 'JMPIF1 'JMPIF) ,label)
  5719.                            codelist
  5720.              ) ) ) ) )
  5721. ) )     )  )
  5722.  
  5723. ; compiliere (QUOTE object)
  5724. (defun c-QUOTE ()
  5725.   (test-list *form* 2 2)
  5726.   (let ((value (second *form*)))
  5727.     (make-anode :type 'QUOTE
  5728.                 :sub-anodes '()
  5729.                 :seclass '(NIL . NIL)
  5730.                 :code (if *for-value* `((CONST ,(new-const value))) '() )
  5731. ) ) )
  5732.  
  5733. ; compiliere (THE type form)
  5734. (defun c-THE ()
  5735.   (test-list *form* 3 3)
  5736.   (c-form (third *form*)) ; ignoriere einfach die Typdeklaration
  5737. )
  5738.  
  5739. ; compiliere (DECLARE {declspec}*)
  5740. (defun c-DECLARE ()
  5741.   (test-list *form* 1)
  5742.   (c-error #+DEUTSCH "Deklarationen sind an dieser Stelle nicht erlaubt: ~S"
  5743.            #+ENGLISH "Misplaced declaration: ~S"
  5744.            *form*
  5745. ) )
  5746.  
  5747. ; compiliere (LOAD-TIME-VALUE form [read-only-p])
  5748. (defun c-LOAD-TIME-VALUE ()
  5749.   (test-list *form* 2 3)
  5750.   (let ((form (second *form*))) ; ignoriere read-only-p
  5751.     (make-anode :type 'LOAD-TIME-VALUE
  5752.                 :sub-anodes '()
  5753.                 :seclass '(NIL . NIL)
  5754.                 :code (if *for-value*
  5755.                         `((CONST ,(make-const :value (eval form) :form form)))
  5756.                         '()
  5757.                       )
  5758. ) ) )
  5759.  
  5760. ; compiliere (CATCH tag {form}*)
  5761. (defun c-CATCH ()
  5762.   (test-list *form* 2)
  5763.   (let* ((anode1 (c-form (second *form*) 'ONE))
  5764.          (anode2 (let ((*stackz* (cons 'CATCH *stackz*)))
  5765.                    (c-form `(PROGN ,@(cddr *form*)))
  5766.          )       )
  5767.          (label (make-label *for-value*)))
  5768.     (make-anode :type 'CATCH
  5769.                 :sub-anodes (list anode1 anode2)
  5770.                 :seclass (anodes-seclass-or anode1 anode2)
  5771.                 :code `(,anode1
  5772.                         (CATCH-OPEN ,label)
  5773.                         ,anode2
  5774.                         (CATCH-CLOSE)
  5775.                         ,label
  5776. ) ) )                  )
  5777.  
  5778. ; compiliere (THROW tag form)
  5779. (defun c-THROW ()
  5780.   (test-list *form* 3 3)
  5781.   (let* ((anode1 (c-form (second *form*) 'ONE))
  5782.          (anode2 (let ((*stackz* (cons 1 *stackz*)))
  5783.                    (c-form (third *form*) 'ALL)
  5784.         ))       )
  5785.     (make-anode :type 'THROW
  5786.                 :sub-anodes (list anode1 anode2)
  5787.                 :seclass (cons (car (anodes-seclass-or anode1 anode2)) 'T)
  5788.                 :code `(,anode1 (PUSH) ,anode2 (THROW))
  5789. ) ) )
  5790.  
  5791. ; compiliere (UNWIND-PROTECT form1 {form}*)
  5792. (defun c-UNWIND-PROTECT ()
  5793.   (test-list *form* 2)
  5794.   (let* ((anode1 (let ((*stackz* (cons 'UNWIND-PROTECT *stackz*)))
  5795.                    (c-form (second *form*))
  5796.          )       )
  5797.          (anode2 (let ((*stackz* (cons 'CLEANUP *stackz*)))
  5798.                    (c-form `(PROGN ,@(cddr *form*)) 'NIL)
  5799.          )       )
  5800.          (label (make-label 'NIL)))
  5801.     (make-anode :type 'UNWIND-PROTECT
  5802.                 :sub-anodes (list anode1 anode2)
  5803.                 :seclass (anodes-seclass-or anode1 anode2)
  5804.                 :code `((UNWIND-PROTECT-OPEN ,label)
  5805.                         ,anode1
  5806.                         ,@(case *for-value*
  5807.                             ((NIL) '((VALUES0)))
  5808.                             (ONE '((VALUES1)))
  5809.                             ((T) '())
  5810.                           )
  5811.                         (UNWIND-PROTECT-NORMAL-EXIT)
  5812.                         ,label
  5813.                         ,anode2
  5814.                         (UNWIND-PROTECT-CLOSE ,label)
  5815. ) ) )                  )
  5816.  
  5817. ; compiliere (PROGV form1 form2 {form}*)
  5818. (defun c-PROGV ()
  5819.   (test-list *form* 3)
  5820.   (let ((anode1 (c-form (second *form*) 'ONE)))
  5821.     ; falls form1 konstant=NIL ist, kann man sich das Binden sparen:
  5822.     (if (and (anode-constantp anode1) (null (anode-constant-value anode1)))
  5823.       (c-form `(PROGN ,(third *form*) (PROGN ,@(cdddr *form*))))
  5824.       (let* ((stackz2 (cons 1 *stackz*))
  5825.              (anode2 (let ((*stackz* stackz2))
  5826.                        (c-form (third *form*) 'ONE)
  5827.              )       )
  5828.              (stackz3 (cons 'PROGV *stackz*))
  5829.              (anode3 (let ((*stackz* stackz3))
  5830.                        (c-form `(PROGN ,@(cdddr *form*)))
  5831.              )       )
  5832.              (flag t))
  5833.         ; falls anode3 von keinen Seiteneffekten abhängig ist, kann man sich das
  5834.         ; Binden sparen:
  5835.         (when (null (car (anode-seclass anode3)))
  5836.           (setf (first stackz2) 0)
  5837.           (setf (first stackz3) 0)
  5838.           (setq flag nil)
  5839.         )
  5840.         (make-anode :type 'PROGV
  5841.                     :sub-anodes (list anode1 anode2 anode3)
  5842.                     :seclass (anodes-seclass-or anode1 anode2 anode3)
  5843.                     :code `(,anode1
  5844.                             ,@(if flag '((PUSH)))
  5845.                             ,anode2
  5846.                             ,@(if flag '((PROGV)))
  5847.                             ,anode3
  5848.                             ,@(if flag
  5849.                                 `((UNWIND ,stackz3 ,*stackz* ,*for-value*))
  5850.                                 ; wird expandiert zu '((UNBIND1) (SKIPSP 1))
  5851.                            )  )
  5852. ) ) ) ) )
  5853.  
  5854. ; compiliere (MULTIPLE-VALUE-PROG1 form1 {form}*)
  5855. ; falls Werte nicht gebraucht werden: einfaches PROGN. Sonst: falls {form}*
  5856. ; seiteneffektfrei, nur form1, sonst: Werte von form1 auf den Stack legen und
  5857. ; nachher mit Funktion VALUES wieder einsammeln.
  5858. (defun c-MULTIPLE-VALUE-PROG1 ()
  5859.   (test-list *form* 2)
  5860.   (case *for-value*
  5861.     (ALL
  5862.      (let* ((stackz1 (cons 'MVCALLP *stackz*))
  5863.             (anode1 (let ((*stackz* stackz1))
  5864.                       (c-form (second *form*))
  5865.             )       )
  5866.             (anode2 (let ((*stackz* (cons 'MVCALL *stackz*)))
  5867.                       (c-form `(PROGN ,@(cddr *form*)) 'NIL)
  5868.            ))       )
  5869.        (make-anode :type 'MULTIPLE-VALUE-PROG1
  5870.                    :sub-anodes (list anode1 anode2)
  5871.                    :seclass (anodes-seclass-or anode1 anode2)
  5872.                    :code
  5873.                       (if (cdr (anode-seclass anode2))
  5874.                         `((CONST , #+CLISP (make-const :value #'values
  5875.                                                        :form '(function values)
  5876.                                            )
  5877.                                    #-CLISP (new-const 'values)
  5878.                           )
  5879.                           (MVCALLP)
  5880.                           ,anode1
  5881.                           (MV-TO-STACK)
  5882.                           ,anode2
  5883.                           (MVCALL))
  5884.                         (prog2 (setf (first stackz1) 0) `(,anode1))
  5885.                       )
  5886.     )) )
  5887.     (ONE (c-form `(PROG1 ,@(cdr *form*))))
  5888.     ((NIL) (c-form `(PROGN ,@(cdr *form*))))
  5889. ) )
  5890.  
  5891. ; compiliere (MULTIPLE-VALUE-CALL form1 {form}*)
  5892. (defun c-MULTIPLE-VALUE-CALL ()
  5893.   (test-list *form* 2)
  5894.   (if (null (cddr *form*))
  5895.     ; (c-form `(SYS::%FUNCALL ,(second *form*))) ; 0 Argumente zu form1
  5896.     (c-FUNCTION-CALL (second *form*) '())
  5897.     (let* ((anode1 (c-form (second *form*) 'ONE))
  5898.            #+COMPILER-DEBUG (anodelist (list anode1))
  5899.            (codelist '()))
  5900.       (push anode1 codelist)
  5901.       (push '(MVCALLP) codelist)
  5902.       (do ((Lr (cddr *form*))
  5903.            (i 0 (1+ i)))
  5904.           ((null Lr))
  5905.         (let* ((formi (pop Lr))
  5906.                (anodei
  5907.                  (let ((*stackz* (cons (if (zerop i) 'MVCALLP 'MVCALL) *stackz*)))
  5908.                    (c-form formi 'ALL)
  5909.               )) )
  5910.           #+COMPILER-DEBUG (push anodei anodelist)
  5911.           (push anodei codelist)
  5912.           (push '(MV-TO-STACK) codelist)
  5913.       ) )
  5914.       (push '(MVCALL) codelist)
  5915.       (make-anode :type 'MULTIPLE-VALUE-CALL
  5916.                   :sub-anodes (nreverse anodelist)
  5917.                   :seclass '(T . T)
  5918.                   :code (nreverse codelist)
  5919. ) ) ) )
  5920.  
  5921. ; compiliere (MULTIPLE-VALUE-LIST form)
  5922. (defun c-MULTIPLE-VALUE-LIST ()
  5923.   (test-list *form* 2 2)
  5924.   (if *for-value*
  5925.     (let ((anode1 (c-form (second *form*) 'ALL)))
  5926.       (make-anode :type 'MULTIPLE-VALUE-LIST
  5927.                   :sub-anodes (list anode1)
  5928.                   :seclass (anodes-seclass-or anode1)
  5929.                   :code `(,anode1 (MV-TO-LIST))
  5930.     ) )
  5931.     (c-form (second *form*))
  5932. ) )
  5933.  
  5934. ; Stellt fest, ob eine SETQ-Argumentliste Symbol-Macros zuweist.
  5935. (defun setqlist-macrop (l)
  5936.   (do ((l l (cddr l)))
  5937.       ((null l) nil)
  5938.     (let ((s (car l)))
  5939.       (when (and (symbolp s) (symbol-macro-p (venv-search-macro s))) (return t))
  5940. ) ) )
  5941.  
  5942. ; compiliere (SETQ {symbol form}*)
  5943. ; alle Zuweisungen nacheinander durchführen
  5944. (defun c-SETQ ()
  5945.   (test-list *form* 1)
  5946.   (when (evenp (length *form*))
  5947.     (c-error #+DEUTSCH "Ungerade viele Argumente zu SETQ: ~S"
  5948.              #+ENGLISH "Odd number of arguments to SETQ: ~S"
  5949.              *form*
  5950.   ) )
  5951.   (if (null (cdr *form*))
  5952.     (c-NIL) ; (SETQ) == (PROGN) == NIL
  5953.     (if (setqlist-macrop (cdr *form*))
  5954.       (c-form ; (SETF ...) statt (SETQ ...), macroexpandieren
  5955.         (funcall (macro-function 'SETF) (cons 'SETF (cdr *form*))
  5956.                  (vector *venv* *fenv*)
  5957.       ) )
  5958.       (do ((L (cdr *form*) (cddr L))
  5959.            #+COMPILER-DEBUG (anodelist '())
  5960.            (seclass '(NIL . NIL))
  5961.            (codelist '()))
  5962.           ((null L)
  5963.            (make-anode
  5964.              :type 'SETQ
  5965.              :sub-anodes (nreverse anodelist)
  5966.              :seclass seclass
  5967.              :code (nreverse codelist)
  5968.           ))
  5969.         (let* ((symboli (first L))
  5970.                (formi (second L))
  5971.                (anodei (c-form formi 'ONE)))
  5972.           #+COMPILER-DEBUG (push anodei anodelist)
  5973.           (if (symbolp symboli)
  5974.             (progn
  5975.               (push anodei codelist)
  5976.               (seclass-or-f seclass anodei)
  5977.               (let ((setteri (c-VARSET symboli anodei)))
  5978.                 (push setteri codelist)
  5979.                 (seclass-or-f seclass setteri)
  5980.             ) )
  5981.             (progn
  5982.               (catch 'c-error
  5983.                 (c-error #+DEUTSCH "Zuweisung auf ~S unmöglich, da kein Symbol."
  5984.                          #+ENGLISH "Cannot assign to non-symbol ~S."
  5985.                          symboli
  5986.               ) )
  5987.               (push '(VALUES1) codelist)
  5988.       ) ) ) )
  5989. ) ) )
  5990.  
  5991. ; compiliere (PSETQ {symbol form}*)
  5992. ; alle Zwischenwerte auf dem Stack retten, erst dann zuweisen
  5993. (defun c-PSETQ ()
  5994.   (test-list *form* 1)
  5995.   (when (evenp (length *form*))
  5996.     (c-error #+DEUTSCH "Ungerade viele Argumente zu PSETQ: ~S"
  5997.              #+ENGLISH "Odd number of arguments to PSETQ: ~S"
  5998.              *form*
  5999.   ) )
  6000.   (if (null (cdr *form*))
  6001.     (c-NIL) ; (PSETQ) == (PROGN) == NIL
  6002.     (if (setqlist-macrop (cdr *form*))
  6003.       (c-form ; (PSETF ...) statt (PSETQ ...), macroexpandieren
  6004.         (funcall (macro-function 'PSETF) (cons 'PSETF (cdr *form*))
  6005.                  (vector *venv* *fenv*)
  6006.       ) )
  6007.       (let ((anodelist '())
  6008.             (setterlist '()))
  6009.         ; Formen und Zuweisungen compilieren:
  6010.         (do ((L (cdr *form*)))
  6011.             ((null L))
  6012.           (let* ((symboli (pop L))
  6013.                  (formi (pop L))
  6014.                  (anodei (c-form formi 'ONE)))
  6015.             (if (symbolp symboli)
  6016.               (progn
  6017.                 (push anodei anodelist)
  6018.                 (push (c-VARSET symboli anodei) setterlist)
  6019.                 (push 0 *stackz*)
  6020.               )
  6021.               (catch 'c-error
  6022.                 (c-error #+DEUTSCH "Zuweisung auf ~S unmöglich, da kein Symbol."
  6023.                          #+ENGLISH "Cannot assign to non-symbol ~S."
  6024.                          symboli
  6025.         ) ) ) ) )
  6026.         ; Versuche, sie so zu reorganisieren, daß möglichst wenige (PUSH)
  6027.         ; und (POP) nötig werden:
  6028.         (let ((codelist1 '())
  6029.               (codelist2 '())
  6030.               ; baue codelist = (nconc codelist1 (nreverse codelist2)) zusammen
  6031.               (seclass '(NIL . NIL))) ; Seiteneffektklasse von codelist insgesamt
  6032.           (do ((anodelistr anodelist (cdr anodelistr))
  6033.                (setterlistr setterlist (cdr setterlistr)))
  6034.               ((null anodelistr))
  6035.             (let ((anode (car anodelistr))
  6036.                   (setter (car setterlistr)))
  6037.               ; Normalerweise wäre vor codelist der anode und ein (PUSH)
  6038.               ; und nach codelist ein (POP) und der setter anzuhängen.
  6039.               ; Dies versuchen wir zu vereinfachen:
  6040.               (cond ((seclasses-commute (anode-seclass setter) seclass)
  6041.                      ; Ziehe den setter nach vorne:
  6042.                      (push setter codelist1)
  6043.                      (push anode codelist1)
  6044.                     )
  6045.                     ((seclasses-commute (anode-seclass anode) seclass)
  6046.                      ; Ziehe den anode nach hinten:
  6047.                      (push anode codelist2)
  6048.                      (push setter codelist2)
  6049.                     )
  6050.                     (t ; keine Vereinfachung möglich
  6051.                      (push '(PUSH) codelist1)
  6052.                      (push anode codelist1)
  6053.                      (push '(POP) codelist2)
  6054.                      (push setter codelist2)
  6055.                      (setf (car *stackz*) 1) ; brauche eine Variable im Stack
  6056.               )     )
  6057.               (setq seclass
  6058.                 (seclass-or-2 seclass
  6059.                   (seclass-or-2 (anode-seclass anode) (anode-seclass setter))
  6060.               ) )
  6061.               (setf *stackz* (cdr *stackz*))
  6062.           ) )
  6063.           ; *stackz* ist nun wieder auf dem alten Niveau.
  6064.           (when *for-value* (push '(NIL) codelist2))
  6065.           (make-anode
  6066.             :type 'PSETQ
  6067.             :sub-anodes (nreverse anodelist)
  6068.             :seclass seclass
  6069.             :code (nconc codelist1 (nreverse codelist2))
  6070. ) ) ) ) ) )
  6071.  
  6072. ; compiliere (MULTIPLE-VALUE-SETQ ({symbol}*) form)
  6073. ; alle gewünschten Werte auf den Stack, dann einzeln herunternehmen und
  6074. ; zuweisen.
  6075. (defun c-MULTIPLE-VALUE-SETQ ()
  6076.   (test-list *form* 3 3)
  6077.   (test-list (second *form*) 0)
  6078.   (if (dolist (s (second *form*) nil)
  6079.         (when (and (symbolp s) (symbol-macro-p (venv-search-macro s))) (return t))
  6080.       )
  6081.     (c-form `(SYSTEM::MULTIPLE-VALUE-SETF ,@(cdr *form*)))
  6082.     (let* ((n (length (second *form*)))
  6083.            (anode1 (c-form (third *form*) 'ALL))
  6084.            (*stackz* *stackz*))
  6085.       (if (zerop n)
  6086.         (make-anode :type 'MULTIPLE-VALUE-SETQ
  6087.                     :sub-anodes (list anode1)
  6088.                     :seclass (anodes-seclass-or anode1)
  6089.                     :code `(,anode1
  6090.                             ,@(if (eq *for-value* 'ALL) '((VALUES1)) '())
  6091.         )                  )
  6092.         (do ((L (second *form*) (cdr L))
  6093.              #+COMPILER-DEBUG (anodelist (list anode1))
  6094.              (seclass (anode-seclass anode1))
  6095.              (codelist '()))
  6096.             ((null L)
  6097.              (if (= n 1)
  6098.                (setq codelist (cdr codelist)) ; letztes (POP) streichen
  6099.                (setq codelist (cons `(NV-TO-STACK ,n) codelist))
  6100.              )
  6101.              (make-anode
  6102.                :type 'MULTIPLE-VALUE-SETQ
  6103.                :sub-anodes (nreverse anodelist)
  6104.                :seclass seclass
  6105.                :code (cons anode1 codelist)
  6106.             ))
  6107.           (let ((symbol (car L)))
  6108.             (if (symbolp symbol)
  6109.               (let ((setter (c-VARSET symbol
  6110.                               (make-anode :type 'NOP
  6111.                                           :sub-anodes '()
  6112.                                           :seclass '(NIL . NIL)
  6113.                                           :code '()
  6114.                    ))       ) )
  6115.                 (push setter codelist)
  6116.                 (seclass-or-f seclass setter)
  6117.               )
  6118.               (catch 'c-error
  6119.                 (c-error #+DEUTSCH "Zuweisung auf ~S unmöglich, da kein Symbol."
  6120.                          #+ENGLISH "Cannot assign to non-symbol ~S."
  6121.                          symbol
  6122.           ) ) ) )
  6123.           (push '(POP) codelist)
  6124.           (push 1 *stackz*)
  6125. ) ) ) ) )
  6126.  
  6127. ; compiliere (LET/LET* ({var|(var value)}*) {declaration}* {form}*)
  6128. (defun c-LET/LET* (*-flag)
  6129.   (test-list *form* 2)
  6130.   (test-list (second *form*) 0)
  6131.   (multiple-value-bind (body-rest declarations)
  6132.       (parse-body (cddr *form*) nil (vector *venv* *fenv*))
  6133.     (let ((oldstackz *stackz*)
  6134.           (*stackz* *stackz*)
  6135.           (*denv* *denv*)
  6136.           (*venv* *venv*)
  6137.           (*venvc* *venvc*))
  6138.       (multiple-value-bind (*specials* *ignores* *ignorables*)
  6139.           (process-declarations declarations)
  6140.         ; Special-Variable auf *venv* pushen:
  6141.         (push-specials)
  6142.         ; Syntaxtest der Parameterliste:
  6143.         (multiple-value-bind (symbols initforms) (analyze-letlist (second *form*))
  6144.           (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  6145.           (let ((closuredummy-stackz *stackz*)
  6146.                 (closuredummy-venvc *venvc*))
  6147.             (multiple-value-bind (varlist anodelist stackzlist)
  6148.                 (process-movable-var-list symbols initforms *-flag)
  6149.               (unless *-flag (push 0 *stackz*)) ; Platz für Schluß-Bindungen
  6150.               (let ((body-anode (c-form `(PROGN ,@body-rest)))) ; Body compilieren
  6151.                 ; Überprüfen der Variablen:
  6152.                 (let* ((closurevars (checking-movable-var-list varlist anodelist))
  6153.                        (codelist
  6154.                          `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  6155.                            ,@(if *-flag
  6156.                                ; sequentielles Binden der Variablen
  6157.                                (mapcap #'c-bind-movable-var-anode varlist anodelist)
  6158.                                ; paralleles Binden der Variablen:
  6159.                                ; Variable darf erst am Schluß gebunden werden,
  6160.                                ; falls sie SPECIAL ist und nachfolgende Anodes
  6161.                                ; von ihrem Wert abhängen können.
  6162.                                (let ((bind-afterwards nil))
  6163.                                  (append
  6164.                                    (maplap
  6165.                                      #'(lambda (varlistr anodelistr stackzlistr)
  6166.                                          (let ((var (car varlistr))
  6167.                                                (anode (car anodelistr)))
  6168.                                            (if (and (var-specialp var)
  6169.                                                     (let ((symbol (var-name var)))
  6170.                                                       (some
  6171.                                                         #'(lambda (other-anode)
  6172.                                                             ; hängt der Wert von other-anode möglicherweise
  6173.                                                             ; vom Wert von var ab?
  6174.                                                             (let ((uses (car (anode-seclass other-anode))))
  6175.                                                               (or (eq uses 'T) (member symbol uses))
  6176.                                                           ) )
  6177.                                                         (cdr anodelistr)
  6178.                                                )    ) )
  6179.                                              (let* ((stackz (car stackzlistr))
  6180.                                                     (dummyvar ; Hilfsvariable im Stack
  6181.                                                       (make-var :name (gensym) :specialp nil
  6182.                                                                 :closurep nil :stackz stackz
  6183.                                                    )) )
  6184.                                                (push (list dummyvar var (cdr *stackz*)) bind-afterwards)
  6185.                                                (push (car stackz) (cdr *stackz*)) ; Platz für 1 Schluß-Bindung mehr
  6186.                                                (setf (car stackz) 1) ; Platz für Hilfsvariable im Stack merken
  6187.                                                (c-bind-movable-var-anode dummyvar anode)
  6188.                                              )
  6189.                                              (c-bind-movable-var-anode var anode)
  6190.                                        ) ) )
  6191.                                      varlist anodelist stackzlist
  6192.                                    )
  6193.                                    (mapcap
  6194.                                      #'(lambda (bind)
  6195.                                          (let ((dummyvar (first bind)) ; Hilfsvariable im Stack
  6196.                                                (var (second bind)) ; SPECIAL-Variable
  6197.                                                (stackz (third bind))) ; Stackzustand vor Aufbau der Schluß-Bindung
  6198.                                            `((GET ,dummyvar ,*venvc* ,stackz)
  6199.                                              ,@(c-bind-movable-var var)
  6200.                                             )
  6201.                                        ) )
  6202.                                      (nreverse bind-afterwards)
  6203.                                    )
  6204.                              ) ) )
  6205.                            ,body-anode
  6206.                            (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  6207.                        )  )
  6208.                        (anode
  6209.                          (make-anode
  6210.                            :type (if *-flag 'LET* 'LET)
  6211.                            :sub-anodes `(,@anodelist ,body-anode)
  6212.                            :seclass (seclass-without
  6213.                                       (anodelist-seclass-or `(,@anodelist ,body-anode))
  6214.                                       varlist
  6215.                                     )
  6216.                            :stackz oldstackz
  6217.                            :code codelist
  6218.                       )) )
  6219.                   (when closurevars
  6220.                     (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  6221.                     (setf (first closuredummy-venvc)
  6222.                       (cons closurevars closuredummy-stackz)
  6223.                   ) )
  6224.                   (optimize-var-list varlist)
  6225.                   anode
  6226. ) ) ) ) ) ) ) ) )
  6227.  
  6228. ; compiliere (LOCALLY {declaration}* {form}*)
  6229. (defun c-LOCALLY (&optional (c #'c-form)) ; vgl. c-LET/LET*
  6230.   (test-list *form* 1)
  6231.   (multiple-value-bind (body-rest declarations)
  6232.       (parse-body (cdr *form*) nil (vector *venv* *fenv*))
  6233.     (let ((*venv* *venv*))
  6234.       (multiple-value-bind (*specials* ignores ignorables)
  6235.           (process-declarations declarations)
  6236.         (declare (ignore ignores ignorables))
  6237.         ; Special-Variable auf *venv* pushen:
  6238.         (push-specials)
  6239.         (funcall c `(PROGN ,@body-rest))
  6240. ) ) ) )
  6241.  
  6242. ; compiliere (MULTIPLE-VALUE-BIND ({var}*) form1 {declaration}* {form}*)
  6243. (defun c-MULTIPLE-VALUE-BIND ()
  6244.   (test-list *form* 3)
  6245.   (test-list (second *form*) 0)
  6246.   (let ((symbols (second *form*)))
  6247.     (dolist (sym symbols)
  6248.       (unless (symbolp sym)
  6249.         (c-error #+DEUTSCH "Nur Symbole können Variable sein, nicht ~S"
  6250.                  #+ENGLISH "Only symbols may be used as variables, not ~S"
  6251.                  sym
  6252.     ) ) )
  6253.     (if (= (length symbols) 1)
  6254.       (c-form `(LET ((,(first symbols) ,(third *form*))) ,@(cdddr *form*)))
  6255.       (multiple-value-bind (body-rest declarations)
  6256.           (parse-body (cdddr *form*) nil (vector *venv* *fenv*))
  6257.         (let ((oldstackz *stackz*)
  6258.               (*stackz* *stackz*)
  6259.               (*denv* *denv*)
  6260.               (*venv* *venv*)
  6261.               (*venvc* *venvc*))
  6262.           (multiple-value-bind (*specials* *ignores* *ignorables*)
  6263.               (process-declarations declarations)
  6264.             ; Special-Variable auf *venv* pushen:
  6265.             (push-specials)
  6266.             (if (null symbols) ; leere Variablenliste -> gar nichts binden
  6267.               (let* ((anode1 (c-form (third *form*) 'NIL))
  6268.                      (anode2 (c-form `(PROGN ,@(cdddr *form*)))))
  6269.                 (make-anode :type 'MULTIPLE-VALUE-BIND
  6270.                   :sub-anodes (list anode1 anode2)
  6271.                   :seclass (anodes-seclass-or anode1 anode2)
  6272.                   :code `(,anode1 ,anode2)
  6273.               ) )
  6274.               (let ((anode1 (c-form (third *form*) 'ALL)))
  6275.                 (push nil *venvc*) ; Sichtbarkeit von Closure-Dummyvar
  6276.                 (multiple-value-bind (varlist stackvarlist)
  6277.                     (process-fixed-var-list symbols)
  6278.                   (push 0 *stackz*) ; Platz für Closure-Dummyvar
  6279.                   (let* ((closuredummy-stackz *stackz*)
  6280.                          (closuredummy-venvc *venvc*)
  6281.                          (stackzlist
  6282.                            (do* ((varlistr varlist (cdr varlistr))
  6283.                                  (L '()))
  6284.                                 ((null varlistr) (nreverse L))
  6285.                              (let ((var (car varlistr)))
  6286.                                (push-*venv* var)
  6287.                                (push *stackz* L) (bind-fixed-var-2 var)
  6288.                          ) ) )
  6289.                          (body-anode ; Body compilieren
  6290.                            (c-form `(PROGN ,@body-rest))
  6291.                          )
  6292.                          ; Überprüfen der Variablen:
  6293.                          (closurevars (checking-fixed-var-list varlist))
  6294.                          (codelist ; Code generieren
  6295.                            `(,anode1
  6296.                              (NV-TO-STACK ,(length symbols))
  6297.                              ,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  6298.                              ,@ ; Binden von special- oder Closure-Variablen:
  6299.                                (do ((stackvarlistr stackvarlist (cdr stackvarlistr))
  6300.                                     (stackzlistr stackzlist (cdr stackzlistr))
  6301.                                     (varlistr varlist (cdr varlistr))
  6302.                                     (L '()))
  6303.                                    ((null varlistr) (nreverse L))
  6304.                                  (setq L
  6305.                                    (append
  6306.                                      (reverse
  6307.                                        (c-bind-fixed-var
  6308.                                          (car varlistr)
  6309.                                          (car stackvarlistr)
  6310.                                          (car stackzlistr)
  6311.                                      ) )
  6312.                                      L
  6313.                                ) ) )
  6314.                              ,body-anode
  6315.                              (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  6316.                          )  )
  6317.                          (anode
  6318.                            (make-anode
  6319.                              :type 'MULTIPLE-VALUE-BIND
  6320.                              :sub-anodes (list anode1 body-anode)
  6321.                              :seclass (seclass-without
  6322.                                         (anodes-seclass-or anode1 body-anode)
  6323.                                         varlist
  6324.                                       )
  6325.                              :stackz oldstackz
  6326.                              :code codelist
  6327.                         )) )
  6328.                     (when closurevars
  6329.                       (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  6330.                       (setf (first closuredummy-venvc)
  6331.                         (cons closurevars closuredummy-stackz)
  6332.                     ) )
  6333.                     (optimize-var-list varlist)
  6334.                     anode
  6335. ) ) ) ) ) ) ) ) ) )
  6336.  
  6337. ; compiliere (COMPILER-LET ({var|(var value)}*) {form}*)
  6338. (defun c-COMPILER-LET (&optional (c #'c-form))
  6339.   (test-list *form* 2)
  6340.   (test-list (second *form*) 0)
  6341.   (do ((L (second *form*) (cdr L))
  6342.        (varlist '())
  6343.        (valueslist '()))
  6344.       ((null L)
  6345.        (progv (nreverse varlist) (nreverse valueslist)
  6346.          (funcall c `(PROGN ,@(cddr *form*)) )
  6347.       ))
  6348.     (cond ((symbolp (car L)) (push (car L) varlist) (push nil valueslist))
  6349.           ((and (consp (car L)) (symbolp (caar L)) (consp (cdar L)) (null (cddar L)))
  6350.            (push (caar L) varlist) (push (eval (cadar L)) valueslist))
  6351.           (t (catch 'c-error
  6352.                (c-error #+DEUTSCH "Falsche Syntax in COMPILER-LET: ~S"
  6353.                         #+ENGLISH "Illegal syntax in COMPILER-LET: ~S"
  6354.                         (car L)
  6355.     )     )  ) )
  6356. ) )
  6357.  
  6358. (macrolet ((check-blockname (name)
  6359.              `(unless (symbolp ,name)
  6360.                 (catch 'c-error
  6361.                   (c-error #+DEUTSCH "Blockname muß ein Symbol sein, nicht ~S"
  6362.                            #+ENGLISH "Block name must be a symbol, not ~S"
  6363.                            ,name
  6364.                 ) )
  6365.                 (setq ,name NIL) ; Default-Blockname
  6366.               )
  6367.           ))
  6368.  
  6369. ; compiliere (BLOCK name {form}*)
  6370. (defun c-BLOCK ()
  6371.   (test-list *form* 2)
  6372.   (let ((name (second *form*)))
  6373.     (check-blockname name)
  6374.     (let* ((*stackz* (cons 'BLOCK *stackz*)) ; Block-Frame
  6375.            (label (make-label *for-value*))
  6376.            (block (make-block :fnode *func* :label label
  6377.                     :consvar (make-var :name (gensym) :specialp nil
  6378.                                        :closurep nil :stackz *stackz*
  6379.                              )
  6380.                     :stackz *stackz* :used-far nil :for-value *for-value*
  6381.            )      )
  6382.            (*benv* (cons (cons name block) *benv*)) ; Block aktivieren
  6383.            (anode (c-form `(PROGN ,@(cddr *form*))))
  6384.           )
  6385.       (if (block-used-far block)
  6386.         (make-anode :type 'BLOCK
  6387.                     :sub-anodes (list anode)
  6388.                     :seclass (anodes-seclass-or anode)
  6389.                     :code `((BLOCK-OPEN ,(new-const name) ,label)
  6390.                             ,anode
  6391.                             (BLOCK-CLOSE)
  6392.                             ,label
  6393.         )                  )
  6394.         (progn
  6395.           (setf (first *stackz*) 0) ; brauche keinen Blockframe
  6396.           (make-anode :type 'BLOCK
  6397.                       :sub-anodes (list anode)
  6398.                       :seclass (anodes-seclass-or anode)
  6399.                       :code `(,anode ,label)
  6400. ) ) ) ) ) )
  6401.  
  6402. ; compiliere (RETURN-FROM name [form])
  6403. (defun c-RETURN-FROM ()
  6404.   (test-list *form* 2 3)
  6405.   (let ((name (second *form*)))
  6406.     (check-blockname name)
  6407.     (let ((a (benv-search name)))
  6408.       (cond ((null a) ; dieser Blockname ist unsichtbar
  6409.              (c-error #+DEUTSCH "RETURN-FROM auf Block ~S an dieser Stelle nicht möglich."
  6410.                       #+ENGLISH "RETURN-FROM block ~S is impossible from here."
  6411.                       name
  6412.             ))
  6413.             ((block-p a) ; in *benv* ohne %benv% sichtbar
  6414.              (let ((anode (c-form (third *form*) (block-for-value a))))
  6415.                (if (eq (block-fnode a) *func*)
  6416.                  ; selbe Funktionen
  6417.                  (make-anode
  6418.                    :type 'RETURN-FROM
  6419.                    :sub-anodes (list anode)
  6420.                    :seclass '(T . T)
  6421.                    :code `(,anode
  6422.                            (UNWIND ,*stackz* ,(cdr (block-stackz a)) ,(block-for-value a))
  6423.                            (JMP ,(block-label a))
  6424.                  )        )
  6425.                  ; verschiedene Funktionen
  6426.                  (progn
  6427.                    (unless *no-code*
  6428.                      ; in alle dazwischenliegenden Funktionen diesen Block eintragen:
  6429.                      (do ((fnode *func* (fnode-enclosing fnode)))
  6430.                          ((eq fnode (block-fnode a)))
  6431.                        (pushnew a (fnode-blocks fnode))
  6432.                      )
  6433.                      (setf (block-used-far a) t)
  6434.                    )
  6435.                    (make-anode
  6436.                      :type 'RETURN-FROM
  6437.                      :sub-anodes (list anode)
  6438.                      :seclass '(T . T)
  6439.                      :code `(,anode
  6440.                              ,@(if (not (block-for-value a)) '((VALUES0)))
  6441.                              (RETURN-FROM ,a)
  6442.                    )        )
  6443.             )) ) )
  6444.             ((consp a) ; in %benv% sichtbar
  6445.              (let ((anode (c-form (third *form*) 'ALL)))
  6446.                (make-anode
  6447.                  :type 'RETURN-FROM
  6448.                  :sub-anodes (list anode)
  6449.                  :seclass '(T . T)
  6450.                  :code `(,anode
  6451.                          (RETURN-FROM ,(new-const a))
  6452.             )) )        )
  6453.             (t (compiler-error 'c-RETURN-FROM))
  6454. ) ) ) )
  6455.  
  6456. ) ; macrolet
  6457.  
  6458. ; compiliere (TAGBODY {tag|form}*)
  6459. (defun c-TAGBODY ()
  6460.   (test-list *form* 1)
  6461.   (multiple-value-bind (taglist labellist)
  6462.     (do ((L (cdr *form*) (cdr L))
  6463.          (taglist '())
  6464.          (labellist '()))
  6465.         ((null L) (values (nreverse taglist) (nreverse labellist)))
  6466.       (let ((item (car L)))
  6467.         (if (atom item)
  6468.           (if (or (and (symbolp item) (not (null item))) (numberp item))
  6469.             ; Symbol NIL wird ausgeschlossen, weil zweideutig (ist auch Liste!).
  6470.             ; Andere Zahlen werden zugelassen, damit - ebenso wie 3.3.2 - auch
  6471.             ; 3.3 ein zulässiges Sprungziel ist.
  6472.             (progn
  6473.               (push item taglist)
  6474.               (push (make-label 'NIL) labellist)
  6475.             )
  6476.             (catch 'c-error
  6477.               (c-error #+DEUTSCH "Nur Zahlen und Symbole sind zulässige Sprungziele, nicht aber ~S"
  6478.                        #+ENGLISH "Only numbers and symbols are valid tags, not ~S"
  6479.                        item
  6480.     ) ) ) ) ) )
  6481.     (let* ((*stackz* (cons 0 *stackz*)) ; evtl. TAGBODY-Frame
  6482.            (tagbody (make-tagbody :fnode *func* :labellist labellist
  6483.                       :consvar (make-var :name (gensym) :specialp nil
  6484.                                          :closurep nil :stackz *stackz*
  6485.                                )
  6486.                       :stackz *stackz*
  6487.                       :used-far (make-array (length taglist) :fill-pointer 0)
  6488.            )        )
  6489.            (*genv* (cons (cons (apply #'vector taglist) tagbody) *genv*))
  6490.              ; Tagbody aktivieren
  6491.            (codelist '())
  6492.            #+COMPILER-DEBUG (anodelist '())
  6493.            (seclass '(NIL . NIL)))
  6494.       ; Inneres des Tagbody compilieren:
  6495.       (do ((formlistr (cdr *form*) (cdr formlistr))
  6496.            (taglistr taglist)
  6497.            (labellistr labellist))
  6498.           ((null formlistr)
  6499.            #+COMPILER-DEBUG (setq anodelist (nreverse anodelist))
  6500.            (setq codelist (nreverse codelist))
  6501.           )
  6502.         (let ((formi (car formlistr)))
  6503.           (if (atom formi)
  6504.             (when (and (consp taglistr) (eql formi (car taglistr)))
  6505.               ; Tag wiedergefunden
  6506.               (pop taglistr) (push (pop labellistr) codelist)
  6507.             )
  6508.             (let ((anodei (c-form formi 'NIL)))
  6509.               #+COMPILER-DEBUG (push anodei anodelist)
  6510.               (seclass-or-f seclass anodei)
  6511.               (push anodei codelist)
  6512.       ) ) ) )
  6513.       (if (> (length (tagbody-used-far tagbody)) 0)
  6514.         (let* ((used-tags (tagbody-used-far tagbody))
  6515.                (l (length used-tags))
  6516.                (used-label-list
  6517.                  (do ((i 0 (1+ i))
  6518.                       (l1 '()))
  6519.                      ((= i l) (nreverse l1))
  6520.                    (push
  6521.                      (elt labellist (position (aref used-tags i) taglist :test #'eql))
  6522.                      l1
  6523.               )) ) )
  6524.           (setf (first *stackz*) `(TAGBODY ,l))
  6525.           (setq codelist
  6526.             `((TAGBODY-OPEN ,l ,@used-label-list)
  6527.               ,@codelist
  6528.               (TAGBODY-CLOSE-NIL)
  6529.         ) )  )
  6530.         (when *for-value* (setq codelist `(,@codelist (NIL))))
  6531.       )
  6532.       (make-anode :type 'TAGBODY
  6533.                   :sub-anodes anodelist
  6534.                   :seclass seclass
  6535.                   :code codelist
  6536. ) ) ) )
  6537.  
  6538. ; compiliere (GO tag)
  6539. (defun c-GO ()
  6540.   (test-list *form* 2 2)
  6541.   (let ((tag (second *form*)))
  6542.     (unless (or (and (symbolp tag) (not (null tag))) (numberp tag))
  6543.       (c-error #+DEUTSCH "Sprungziel muß ein Symbol oder eine Zahl sein, nicht ~S"
  6544.                #+ENGLISH "Tag must be a symbol or a number, not ~S"
  6545.                tag
  6546.     ) )
  6547.     (multiple-value-bind (a b) (genv-search tag)
  6548.       (cond ((null a) ; dieser Tag ist unsichtbar
  6549.              (c-error #+DEUTSCH "GO auf Tag ~S an dieser Stelle nicht möglich."
  6550.                       #+ENGLISH "GO to tag ~S is impossible from here."
  6551.                       tag
  6552.             ))
  6553.             ((tagbody-p a) ; in *genv* ohne %genv% sichtbar
  6554.              (if (eq (tagbody-fnode a) *func*)
  6555.                ; selbe Funktionen
  6556.                (make-anode
  6557.                  :type 'GO
  6558.                  :sub-anodes '()
  6559.                  :seclass '(T . T)
  6560.                  :code `((UNWIND ,*stackz* ,(tagbody-stackz a) nil)
  6561.                          (JMP ,(nth b (tagbody-labellist a)))
  6562.                )        )
  6563.                ; verschiedene Funktionen
  6564.                (let ((index 0))
  6565.                  (unless *no-code*
  6566.                    (setq index
  6567.                      (do* ((v (tagbody-used-far a))
  6568.                            (l (length v))
  6569.                            (i 0 (1+ i)))
  6570.                           ((= i l) (vector-push tag v) l)
  6571.                        (if (eql (aref v i) tag) (return i))
  6572.                    ) )
  6573.                    ; (aref (tagbody-used-far a) index) = tag
  6574.                    ; in alle dazwischenliegenden Funktionen diesen Tagbody eintragen:
  6575.                    (do ((fnode *func* (fnode-enclosing fnode)))
  6576.                        ((eq fnode (tagbody-fnode a)))
  6577.                      (pushnew a (fnode-tagbodys fnode))
  6578.                  ) )
  6579.                  (make-anode
  6580.                    :type 'GO
  6581.                    :sub-anodes '()
  6582.                    :seclass '(T . T)
  6583.                    :code `((VALUES0) (GO ,a ,index))
  6584.                  )
  6585.             )) )
  6586.             ((consp a) ; in %genv% sichtbar
  6587.              (make-anode
  6588.                :type 'GO
  6589.                :sub-anodes '()
  6590.                :seclass '(T . T)
  6591.                :code `((GO ,(new-const a) ,b))
  6592.             ))
  6593.             (t (compiler-error 'c-GO))
  6594. ) ) ) )
  6595.  
  6596. ; compiliere (FUNCTION funname)
  6597. (defun c-FUNCTION ()
  6598.   (test-list *form* 2 3)
  6599.   (let* ((longp (cddr *form*)) ; Flag, ob Langform (FUNCTION name funname)
  6600.          (name (second *form*)))
  6601.     (if (and (not longp) (function-name-p name))
  6602.       (multiple-value-bind (a b c) (fenv-search name)
  6603.         (case a
  6604.           ((NIL)
  6605.            (when *compiling-from-file* ; von COMPILE-FILE aufgerufen?
  6606.              (unless (or (fboundp name) (member name *known-functions* :test #'equal))
  6607.                (pushnew name *unknown-functions* :test #'equal)
  6608.            ) )
  6609.            (make-anode
  6610.              :type 'FUNCTION
  6611.              :sub-anodes '()
  6612.              :seclass '(T . NIL)
  6613.              :code (if (subr-info name)
  6614.                      `((CONST ,(make-const :value (symbol-function name)
  6615.                                            :form `(FUNCTION ,name)
  6616.                       ))       )
  6617.                      `((CONST ,(make-funname-const name)) (SYMBOL-FUNCTION))
  6618.           ))       )
  6619.           (SYSTEM::MACRO
  6620.            (c-error #+DEUTSCH "~S ist keine Funktion, sondern ein lokal definierter Macro."
  6621.                     #+ENGLISH "~S is not a function. It is a locally defined macro."
  6622.                     name
  6623.           ))
  6624.           (GLOBAL ; gefunden in %fenv%
  6625.            (make-anode
  6626.              :type 'FUNCTION
  6627.              :sub-anodes '()
  6628.              :seclass '(T . NIL)
  6629.              :code `((CONST ,(new-const b))
  6630.                      (PUSH)
  6631.                      (CONST ,(new-const c))
  6632.                      (SVREF)
  6633.           ))        )
  6634.           (LOCAL ; gefunden in *fenv* ohne %fenv%
  6635.            (if (const-p b)
  6636.              (make-anode
  6637.                :type 'FUNCTION
  6638.                :sub-anodes '()
  6639.                :seclass '(NIL . NIL)
  6640.                :code `((FCONST ,(const-value b)))
  6641.              )
  6642.              (c-VAR (var-name b))
  6643.           ))
  6644.           (t (compiler-error 'c-FUNCTION))
  6645.       ) )
  6646.       (let ((funname (car (last *form*))))
  6647.         (if (and (consp funname) (eq (car funname) 'LAMBDA) (consp (cdr funname)))
  6648.           (let ((*no-code* (or *no-code* (null *for-value*))))
  6649.             (c-fnode-function
  6650.               (c-lambdabody
  6651.                 (if (and longp (function-name-p name))
  6652.                   name ; angegebener Funktionsname
  6653.                   (symbol-suffix (fnode-name *func*) (incf *anonymous-count*))
  6654.                 )
  6655.                 (cdr funname)
  6656.           ) ) )
  6657.           (c-error #+DEUTSCH "Nur Symbole und Lambda-Ausdrücke sind Namen von Funktionen, nicht ~S"
  6658.                    #+ENGLISH "Only symbols and lambda expressions are function names, not ~S"
  6659.                    funname
  6660. ) ) ) ) ) )
  6661.  
  6662. ; compiliere (%GENERIC-FUNCTION-LAMBDA . lambdabody)
  6663. (defun c-%GENERIC-FUNCTION-LAMBDA ()
  6664.   (test-list *form* 1)
  6665.   (let ((*no-code* (or *no-code* (null *for-value*))))
  6666.     (c-fnode-function
  6667.       (c-lambdabody
  6668.         (symbol-suffix (fnode-name *func*) (incf *anonymous-count*))
  6669.         (cdr *form*)
  6670.         nil
  6671.         t ; gf-p = T, Code für generische Funktion bauen
  6672. ) ) ) )
  6673.  
  6674. ; compiliere (%OPTIMIZE-FUNCTION-LAMBDA reqoptimflags . lambdabody)
  6675. ; reqoptimflags ist eine Liste von Flags, welche Required-Parameter des
  6676. ; lambdabody wegoptimiert werden dürfen. Zu jedem Required-Parameter:
  6677. ; NIL: normal,
  6678. ; T: darf wegoptimiert werden, dann wird daraus GONE gemacht.
  6679. ; NILs am Schluß der Liste dürfen weggelassen werden.
  6680. ; Die Ausgabe enthält zusätzlich zur Funktion die Liste der Wegoptimierten.
  6681. (defmacro %OPTIMIZE-FUNCTION-LAMBDA (reqoptimflags &rest lambdabody)
  6682.   (declare (ignore reqoptimflags))
  6683.   `(CONS (FUNCTION (LAMBDA ,@lambdabody)) NIL) ; ohne Compiler: nicht optimieren
  6684. )
  6685. (defun c-%OPTIMIZE-FUNCTION-LAMBDA ()
  6686.   (test-list *form* 2)
  6687.   (let ((*no-code* (or *no-code* (null *for-value*))))
  6688.     (let* ((reqoptimflags (copy-list (second *form*)))
  6689.            (anode1
  6690.              (c-fnode-function
  6691.                (c-lambdabody
  6692.                  (symbol-suffix (fnode-name *func*) (incf *anonymous-count*))
  6693.                  (cddr *form*)
  6694.                  nil nil reqoptimflags
  6695.            ) ) )
  6696.            (resultflags (mapcar #'(lambda (x) (eq x 'GONE)) reqoptimflags))
  6697.            (anode2 (let ((*stackz* (cons 1 *stackz*))
  6698.                          (*form* `(QUOTE ,resultflags)))
  6699.                      (c-QUOTE)
  6700.           ))       )
  6701.       (make-anode :type '%OPTIMIZE-FUNCTION-LAMBDA
  6702.                   :sub-anodes (list anode1 anode2)
  6703.                   :seclass (anodes-seclass-or anode1 anode2)
  6704.                   :code `(,anode1 (PUSH) ,anode2 (CONS))
  6705. ) ) ) )
  6706.  
  6707. (macrolet ((err-syntax (specform fdef)
  6708.              `(catch 'c-error
  6709.                 (c-error #+DEUTSCH "Falsche Syntax einer Funktionsdefinition in ~S: ~S"
  6710.                          #+ENGLISH "Illegal function definition syntax in ~S: ~S"
  6711.                          ,specform ,fdef
  6712.               ) )
  6713.           ))
  6714.  
  6715. ; compiliere (FLET ({fundef}*) {form}*)
  6716. (defun c-FLET ()
  6717.   (test-list *form* 2)
  6718.   (test-list (second *form*) 0)
  6719.   (multiple-value-bind (namelist fnodelist)
  6720.       (do ((fdefsr (second *form*) (cdr fdefsr))
  6721.            (L1 '())
  6722.            (L2 '()))
  6723.           ((null fdefsr) (values (nreverse L1) (nreverse L2)))
  6724.         (let ((fdef (car fdefsr)))
  6725.           (if (and (consp fdef) (function-name-p (car fdef)) (consp (cdr fdef)))
  6726.             (let ((fnode (c-lambdabody
  6727.                            (symbol-suffix (fnode-name *func*) (car fdef))
  6728.                            (cdr fdef)
  6729.                  ))      )
  6730.               (push (car fdef) L1)
  6731.               (push fnode L2)
  6732.             )
  6733.             (err-syntax 'FLET fdef)
  6734.       ) ) )
  6735.     ; namelist = Liste der Namen, fnodelist = Liste der fnodes der Funktionen
  6736.     (let ((oldstackz *stackz*)
  6737.           (*stackz* *stackz*)
  6738.           (*venvc* *venvc*)
  6739.           (*venv* *venv*))
  6740.       (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  6741.       (let ((closuredummy-stackz *stackz*)
  6742.             (closuredummy-venvc *venvc*))
  6743.         (multiple-value-bind (varlist anodelist *fenv*)
  6744.             (do ((namelistr namelist (cdr namelistr))
  6745.                  (fnodelistr fnodelist (cdr fnodelistr))
  6746.                  (varlist '())
  6747.                  (anodelist '())
  6748.                  (fenv '()))
  6749.                 ((null namelistr)
  6750.                  (values (nreverse varlist) (nreverse anodelist)
  6751.                          (apply #'vector (nreverse (cons *fenv* fenv)))
  6752.                 ))
  6753.               (push (car namelistr) fenv)
  6754.               (let ((fnode (car fnodelistr)))
  6755.                 (if (zerop (fnode-keyword-offset fnode))
  6756.                   ; Funktionsdefinition ist autonom
  6757.                   (push (cons (list fnode) (make-const :value fnode)) fenv)
  6758.                   (progn
  6759.                     (push (c-fnode-function fnode) anodelist)
  6760.                     (push 1 *stackz*)
  6761.                     (let ((var (make-var :name (gensym) :specialp nil
  6762.                                  :constantp nil :usedp t :really-usedp nil
  6763.                                  :closurep nil ; später evtl. auf T gesetzt
  6764.                                  :stackz *stackz* :venvc *venvc*
  6765.                          ))    )
  6766.                       (push (cons (list fnode) var) fenv)
  6767.                       (push var varlist)
  6768.             ) ) ) ) )
  6769.           (apply #'push-*venv* varlist) ; Hilfsvariablen aktivieren
  6770.           (let* ((body-anode ; restliche Formen compilieren
  6771.                    (c-form `(PROGN ,@(cddr *form*)))
  6772.                  )
  6773.                  (closurevars (checking-movable-var-list varlist anodelist))
  6774.                  (anode
  6775.                    (make-anode
  6776.                      :type 'FLET
  6777.                      :sub-anodes `(,@anodelist ,body-anode)
  6778.                      :seclass (seclass-without
  6779.                                 (anodelist-seclass-or `(,@anodelist ,body-anode))
  6780.                                 varlist
  6781.                               )
  6782.                      :code `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  6783.                              ,@(mapcap #'c-bind-movable-var-anode varlist anodelist)
  6784.                              ,body-anode
  6785.                              (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  6786.                    )        )
  6787.                 ))
  6788.             (when closurevars
  6789.               (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  6790.               (setf (first closuredummy-venvc)
  6791.                 (cons closurevars closuredummy-stackz)
  6792.             ) )
  6793.             (optimize-var-list varlist)
  6794.             anode
  6795. ) ) ) ) ) )
  6796.  
  6797. ; compiliere (LABELS ({fundef}*) {form}*)
  6798. (defun c-LABELS ()
  6799.   (test-list *form* 2)
  6800.   (test-list (second *form*) 0)
  6801.   (let ((oldstackz *stackz*)
  6802.         (*stackz* *stackz*)
  6803.         (*venvc* *venvc*)
  6804.         (*venv* *venv*))
  6805.     (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  6806.     (let ((closuredummy-stackz *stackz*)
  6807.           (closuredummy-venvc *venvc*))
  6808.       (multiple-value-bind (namelist varlist lambdanamelist lambdabodylist fenvconslist)
  6809.           (do ((fdefsr (second *form*) (cdr fdefsr))
  6810.                (L1 '())
  6811.                (L2 '())
  6812.                (L3 '())
  6813.                (L4 '())
  6814.                (L5 '()))
  6815.               ((null fdefsr)
  6816.                (values (nreverse L1) (nreverse L2) (nreverse L3) (nreverse L4) (nreverse L5))
  6817.               )
  6818.             (let ((fdef (car fdefsr)))
  6819.               (if (and (consp fdef) (function-name-p (car fdef)) (consp (cdr fdef)))
  6820.                 (progn
  6821.                   (push (car fdef) L1)
  6822.                   (push 1 *stackz*)
  6823.                   (push (make-var :name (gensym) :specialp nil
  6824.                                   :constantp nil :usedp t :really-usedp nil
  6825.                                   :closurep nil ; später evtl. auf T gesetzt
  6826.                                   :stackz *stackz* :venvc *venvc*
  6827.                         )
  6828.                         L2
  6829.                   )
  6830.                   (push (symbol-suffix (fnode-name *func*) (car fdef)) L3)
  6831.                   (push (cdr fdef) L4)
  6832.                   (push
  6833.                     (cons
  6834.                       ; fdescr, bestehend aus:
  6835.                       (cons nil ; Platz für den FNODE
  6836.                         (cons 'LABELS
  6837.                           (multiple-value-list ; Werten von analyze-lambdalist
  6838.                             (analyze-lambdalist (cadr fdef))
  6839.                       ) ) )
  6840.                       ; Variable
  6841.                       (car L2)
  6842.                     )
  6843.                     L5
  6844.                 ) )
  6845.                 (err-syntax 'LABELS fdef)
  6846.           ) ) )
  6847.         ; namelist = Liste der Namen, varlist = Liste der Variablen,
  6848.         ; lambdanamelist = Liste der Dummynamen der Funktionen,
  6849.         ; lambdabodylist = Liste der Lambdabodys der Funktionen,
  6850.         ; fenvconslist = Liste der Conses (fdescr . var) für *fenv*
  6851.         ; (jeweils fdescr noch ohne den fnode, der kommt erst später hinein).
  6852.         (let ((*fenv* ; Funktionsnamen aktivieren
  6853.                 (do ((namelistr namelist (cdr namelistr))
  6854.                      (fenvconslistr fenvconslist (cdr fenvconslistr))
  6855.                      (L nil))
  6856.                     ((null namelistr)
  6857.                      (push *fenv* L)
  6858.                      (apply #'vector (nreverse L))
  6859.                     )
  6860.                   (push (car namelistr) L)
  6861.                   (push (car fenvconslistr) L)
  6862.              )) )
  6863.           (apply #'push-*venv* varlist) ; Hilfsvariablen aktivieren
  6864.           (let* ((fnodelist ; Funktionen compilieren
  6865.                    (mapcar #'c-lambdabody lambdanamelist lambdabodylist fenvconslist)
  6866.                  )
  6867.                  (anodelist
  6868.                    (mapcar #'(lambda (fnode var)
  6869.                                (c-fnode-function fnode (cdr (var-stackz var)))
  6870.                              )
  6871.                            fnodelist varlist
  6872.                  ) )
  6873.                  (body-anode ; restliche Formen compilieren
  6874.                    (c-form `(PROGN ,@(cddr *form*)))
  6875.                 ))
  6876.             ; die Variablen, zu denen die Funktion autonom war, werden nach-
  6877.             ; träglich zu Konstanten erklärt:
  6878.             (do ((varlistr varlist (cdr varlistr))
  6879.                  (fnodelistr fnodelist (cdr fnodelistr)))
  6880.                 ((null varlistr))
  6881.               (let ((var (car varlistr))
  6882.                     (fnode (car fnodelistr)))
  6883.                 (when (zerop (fnode-keyword-offset fnode))
  6884.                   ; Funktionsdefinition ist autonom
  6885.                   (setf (var-constantp var) t)
  6886.                   (setf (var-constant var) (new-const fnode))
  6887.             ) ) )
  6888.             (let* ((closurevars (checking-movable-var-list varlist anodelist))
  6889.                    (anode
  6890.                      (make-anode
  6891.                        :type 'LABELS
  6892.                        :sub-anodes `(,@anodelist ,body-anode)
  6893.                        :seclass (seclass-without
  6894.                                   (anodelist-seclass-or `(,@anodelist ,body-anode))
  6895.                                   varlist
  6896.                                 )
  6897.                        :code `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  6898.                                ,@(mapcap #'c-bind-movable-var-anode varlist anodelist)
  6899.                                ,body-anode
  6900.                                (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  6901.                      )        )
  6902.                   ))
  6903.               (when closurevars
  6904.                 (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  6905.                 (setf (first closuredummy-venvc)
  6906.                   (cons closurevars closuredummy-stackz)
  6907.               ) )
  6908.               (optimize-var-list varlist)
  6909.               anode
  6910. ) ) ) ) ) ) )
  6911.  
  6912. ; compiliere (CLOS:GENERIC-FLET ({genfundefs}*) {form}*)
  6913. (defun c-GENERIC-FLET ()
  6914.   (test-list *form* 2)
  6915.   (test-list (second *form*) 0)
  6916.   (multiple-value-bind (namelist signlist formlist)
  6917.       (do ((fdefsr (second *form*) (cdr fdefsr))
  6918.            (L1 '())
  6919.            (L2 '())
  6920.            (L3 '()))
  6921.           ((null fdefsr) (values (nreverse L1) (nreverse L2) (nreverse L3)))
  6922.         (let ((fdef (car fdefsr)))
  6923.           (if (and (consp fdef) (function-name-p (car fdef)) (consp (cdr fdef)))
  6924.             (let ((name (first fdef)))
  6925.               (push name L1)
  6926.               (push (clos::defgeneric-lambdalist-callinfo 'clos:generic-flet name (second fdef))
  6927.                     L2
  6928.               )
  6929.               (push (clos::make-generic-function-form 'clos:generic-flet
  6930.                       name (second fdef) (cddr fdef) (vector *venv* *fenv*)
  6931.                     )
  6932.                     L3
  6933.             ) )
  6934.             (err-syntax 'CLOS:GENERIC-FLET fdef)
  6935.       ) ) )
  6936.     ; namelist = Liste der Namen,
  6937.     ; signlist = Liste der Signaturen der generischen Funktionen,
  6938.     ; formlist = Liste der Konstruktor-Formen der generischen Funktionen.
  6939.     (let ((oldstackz *stackz*)
  6940.           (*stackz* *stackz*)
  6941.           (*venvc* *venvc*)
  6942.           (*venv* *venv*))
  6943.       (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  6944.       (let ((closuredummy-stackz *stackz*)
  6945.             (closuredummy-venvc *venvc*))
  6946.         (multiple-value-bind (varlist anodelist *fenv*)
  6947.             (do ((namelistr namelist (cdr namelistr))
  6948.                  (signlistr signlist (cdr signlistr))
  6949.                  (formlistr formlist (cdr formlistr))
  6950.                  (varlist '())
  6951.                  (anodelist '())
  6952.                  (fenv '()))
  6953.                 ((null namelistr)
  6954.                  (values (nreverse varlist) (nreverse anodelist)
  6955.                          (apply #'vector (nreverse (cons *fenv* fenv)))
  6956.                 ))
  6957.               (push (car namelistr) fenv)
  6958.               (push (c-form (car formlistr) 'ONE) anodelist)
  6959.               (push 1 *stackz*)
  6960.               (let ((var (make-var :name (gensym) :specialp nil
  6961.                            :constantp nil :usedp t :really-usedp nil
  6962.                            :closurep nil ; später evtl. auf T gesetzt
  6963.                            :stackz *stackz* :venvc *venvc*
  6964.                    ))    )
  6965.                 (push (cons (list* nil 'GENERIC (car signlistr)) var) fenv)
  6966.                 (push var varlist)
  6967.             ) )
  6968.           (apply #'push-*venv* varlist) ; Hilfsvariablen aktivieren
  6969.           (let* ((body-anode ; restliche Formen compilieren
  6970.                    (c-form `(PROGN ,@(cddr *form*)))
  6971.                  )
  6972.                  (closurevars (checking-movable-var-list varlist anodelist))
  6973.                  (anode
  6974.                    (make-anode
  6975.                      :type 'CLOS:GENERIC-FLET
  6976.                      :sub-anodes `(,@anodelist ,body-anode)
  6977.                      :seclass (seclass-without
  6978.                                 (anodelist-seclass-or `(,@anodelist ,body-anode))
  6979.                                 varlist
  6980.                               )
  6981.                      :code `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  6982.                              ,@(mapcap #'c-bind-movable-var-anode varlist anodelist)
  6983.                              ,body-anode
  6984.                              (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  6985.                    )        )
  6986.                 ))
  6987.             (when closurevars
  6988.               (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  6989.               (setf (first closuredummy-venvc)
  6990.                 (cons closurevars closuredummy-stackz)
  6991.             ) )
  6992.             (optimize-var-list varlist)
  6993.             anode
  6994. ) ) ) ) ) )
  6995.  
  6996. ; compiliere (CLOS:GENERIC-LABELS ({genfundefs}*) {form}*)
  6997. (defun c-GENERIC-LABELS ()
  6998.   (test-list *form* 2)
  6999.   (test-list (second *form*) 0)
  7000.   (let ((oldstackz *stackz*)
  7001.         (*stackz* *stackz*)
  7002.         (*venvc* *venvc*)
  7003.         (*venv* *venv*))
  7004.     (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  7005.     (let ((closuredummy-stackz *stackz*)
  7006.           (closuredummy-venvc *venvc*))
  7007.       (multiple-value-bind (namelist varlist fenvconslist formlist)
  7008.           (do ((fdefsr (second *form*) (cdr fdefsr))
  7009.                (L1 '())
  7010.                (L2 '())
  7011.                (L3 '())
  7012.                (L4 '()))
  7013.               ((null fdefsr)
  7014.                (values (nreverse L1) (nreverse L2) (nreverse L3) (nreverse L4))
  7015.               )
  7016.             (let ((fdef (car fdefsr)))
  7017.               (if (and (consp fdef) (function-name-p (car fdef)) (consp (cdr fdef)))
  7018.                 (let ((name (first fdef)))
  7019.                   (push name L1)
  7020.                   (push 1 *stackz*)
  7021.                   (push (make-var :name (gensym) :specialp nil
  7022.                                   :constantp nil :usedp t :really-usedp nil
  7023.                                   :closurep nil ; später evtl. auf T gesetzt
  7024.                                   :stackz *stackz* :venvc *venvc*
  7025.                         )
  7026.                         L2
  7027.                   )
  7028.                   (push (cons
  7029.                           ; fdescr
  7030.                           (list* nil 'GENERIC
  7031.                                  (clos::defgeneric-lambdalist-callinfo 'clos:generic-labels name (second fdef))
  7032.                           )
  7033.                           ; Variable
  7034.                           (car L2)
  7035.                         )
  7036.                         L3
  7037.                   )
  7038.                   (push (clos::make-generic-function-form 'clos:generic-labels
  7039.                           name (second fdef) (cddr fdef) (vector *venv* *fenv*)
  7040.                         )
  7041.                         L4
  7042.                 ) )
  7043.                 (err-syntax 'CLOS:GENERIC-LABELS fdef)
  7044.           ) ) )
  7045.         ; namelist = Liste der Namen, varlist = Liste der Variablen,
  7046.         ; fenvconslist = Liste der Conses (fdescr . var) für *fenv*,
  7047.         ; formlist = Liste der Konstruktor-Formen der generischen Funktionen.
  7048.         (let ((*fenv* ; Funktionsnamen aktivieren
  7049.                 (do ((namelistr namelist (cdr namelistr))
  7050.                      (fenvconslistr fenvconslist (cdr fenvconslistr))
  7051.                      (L nil))
  7052.                     ((null namelistr)
  7053.                      (push *fenv* L)
  7054.                      (apply #'vector (nreverse L))
  7055.                     )
  7056.                   (push (car namelistr) L)
  7057.                   (push (car fenvconslistr) L)
  7058.              )) )
  7059.           (apply #'push-*venv* varlist) ; Hilfsvariablen aktivieren
  7060.           (let* ((anodelist
  7061.                    (mapcar #'(lambda (form) (c-form form 'ONE)) formlist)
  7062.                  )
  7063.                  (body-anode ; restliche Formen compilieren
  7064.                    (c-form `(PROGN ,@(cddr *form*)))
  7065.                  )
  7066.                  (closurevars (checking-movable-var-list varlist anodelist))
  7067.                  (anode
  7068.                    (make-anode
  7069.                      :type 'CLOS:GENERIC-LABELS
  7070.                      :sub-anodes `(,@anodelist ,body-anode)
  7071.                      :seclass (seclass-without
  7072.                                 (anodelist-seclass-or `(,@anodelist ,body-anode))
  7073.                                 varlist
  7074.                               )
  7075.                      :code `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  7076.                              ,@(mapcap #'c-bind-movable-var-anode varlist anodelist)
  7077.                              ,body-anode
  7078.                              (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  7079.                    )        )
  7080.                 ))
  7081.             (when closurevars
  7082.               (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  7083.               (setf (first closuredummy-venvc)
  7084.                 (cons closurevars closuredummy-stackz)
  7085.             ) )
  7086.             (optimize-var-list varlist)
  7087.             anode
  7088. ) ) ) ) ) )
  7089.  
  7090. ) ; macrolet
  7091.  
  7092. ; compiliere (MACROLET ({macrodef}*) {form}*)
  7093. (defun c-MACROLET (&optional (c #'c-form))
  7094.   (test-list *form* 2)
  7095.   (test-list (second *form*) 0)
  7096.   (do ((L1 (second *form*) (cdr L1))
  7097.        (L2 '()))
  7098.       ((null L1)
  7099.        (push *fenv* L2)
  7100.        (let ((*fenv* (apply #'vector (nreverse L2)))) ; *fenv* erweitern
  7101.          (funcall c `(PROGN ,@(cddr *form*))) ; restliche Formen compilieren
  7102.       ))
  7103.     (let* ((macrodef (car L1))
  7104.            (name (car macrodef)))
  7105.       (push name L2)
  7106.       (push #+CLISP (sys::make-macro-expandercons macrodef)
  7107.             #-CLISP (cons 'SYSTEM::MACRO (make-macro-expander macrodef))
  7108.             L2
  7109.   ) ) )
  7110. )
  7111.  
  7112. ; compiliere (SYMBOL-MACROLET ({symdef}*) {declaration}* {form}*)
  7113. (defun c-SYMBOL-MACROLET (&optional (c #'c-form))
  7114.   (test-list *form* 2)
  7115.   (test-list (second *form*) 0)
  7116.   (multiple-value-bind (body-rest declarations)
  7117.       (parse-body (cddr *form*) nil (vector *venv* *fenv*))
  7118.     (let ((*denv* *denv*)
  7119.           (*venv* *venv*))
  7120.       (multiple-value-bind (*specials* *ignores* *ignorables*)
  7121.           (process-declarations declarations)
  7122.         ; Special-Variable auf *venv* pushen:
  7123.         (push-specials)
  7124.         ; Syntaxtest der Parameterliste:
  7125.         (multiple-value-bind (symbols expansions)
  7126.             (do ((L (second *form*) (cdr L))
  7127.                  (symbols nil)
  7128.                  (expansions nil))
  7129.                 ((null L) (values (nreverse symbols) (nreverse expansions)))
  7130.               (let ((symdef (car L)))
  7131.                 (if (and (consp symdef) (symbolp (car symdef))
  7132.                          (consp (cdr symdef)) (null (cddr symdef))
  7133.                     )
  7134.                   (progn (push (first symdef) symbols) (push (second symdef) expansions))
  7135.                   (catch 'c-error
  7136.                     (c-error #+DEUTSCH "Falsche Syntax in SYMBOL-MACROLET: ~S"
  7137.                              #+ENGLISH "Illegal syntax in SYMBOL-MACROLET: ~S"
  7138.                              symdef
  7139.             ) ) ) ) )
  7140.           (dolist (s (intersection *specials* symbols))
  7141.             (catch 'c-error
  7142.               (c-error #+DEUTSCH "~S: Symbol ~S darf nicht gleichzeitig SPECIAL und Makro deklariert werden."
  7143.                        #+ENGLISH "~S: symbol ~S must not be declared SPECIAL and a macro at the same time"
  7144.                        #+FRANCAIS "~S : Le symbole ~S ne peut être déclaré SPECIAL et macro en même temps."
  7145.                        'symbol-macrolet s
  7146.           ) ) )
  7147.           (setq *venv* ; *venv* erweitern
  7148.             (apply #'vector
  7149.               (nconc (mapcan #'(lambda (sym expansion) (list sym (make-symbol-macro expansion)))
  7150.                              symbols expansions
  7151.                      )
  7152.                      (list *venv*)
  7153.           ) ) )
  7154.           (funcall c `(PROGN ,@body-rest)) ; restliche Formen compilieren
  7155. ) ) ) ) )
  7156.  
  7157. ; compiliere (EVAL-WHEN ({situation}*) {form}*)
  7158. (defun c-EVAL-WHEN (&optional (c #'c-form))
  7159.   (test-list *form* 2)
  7160.   (test-list (second *form*) 0)
  7161.   (let ((load-flag nil)
  7162.         (compile-flag nil))
  7163.     (dolist (situation (second *form*))
  7164.       (case situation
  7165.         (LOAD (setq load-flag t))
  7166.         (COMPILE (setq compile-flag t))
  7167.         (EVAL)
  7168.         (T (c-error #+DEUTSCH "Situation bei EVAL-WHEN muß EVAL, LOAD oder COMPILE sein, nicht ~S."
  7169.                     #+ENGLISH "EVAL-WHEN situation must be EVAL or LOAD or COMPILE, but not ~S"
  7170.                     situation
  7171.     ) ) )  )
  7172.     (let ((form `(PROGN ,@(cddr *form*))))
  7173.       (when compile-flag (c-eval-when-compile form))
  7174.       (funcall c (if load-flag form 'NIL))
  7175. ) ) )
  7176.  
  7177. ; compiliere (COND {clause}*)
  7178. (defun c-COND ()
  7179.   (test-list *form* 1)
  7180.   (c-form
  7181.     (let ((clauses (cdr *form*))) ; (COND . clauses) macroexpandieren
  7182.       (if (null clauses)
  7183.         'NIL
  7184.         (let ((clause (car clauses)))
  7185.           (if (atom clause)
  7186.             (c-error #+DEUTSCH "COND-Klausel ohne Test: ~S"
  7187.                      #+ENGLISH "COND clause without test: ~S"
  7188.                      clause
  7189.             )
  7190.             (let ((test (car clause)))
  7191.               (if (cdr clause)
  7192.                 `(IF ,test (PROGN ,@(cdr clause)) (COND ,@(cdr clauses)))
  7193.                 `(OR ,test (COND ,@(cdr clauses)))
  7194. ) ) ) ) ) ) ) )
  7195.  
  7196.  
  7197. ;               ERSTER PASS :   M A C R O S
  7198.  
  7199. ; compiliere (CASE keyform {clause}*)
  7200. (defun c-CASE ()
  7201.   (test-list *form* 1)
  7202.   (let ((keyform (second *form*))
  7203.         (clauses (cddr *form*))
  7204.         ; clauses vereinfachen:
  7205.         (newclauses '())
  7206.         (allkeys '()))
  7207.     (let ((default-passed nil))
  7208.       (dolist (clause clauses)
  7209.         (if (atom clause)
  7210.           (c-error #+DEUTSCH "CASE-Klausel ohne Objekte: ~S"
  7211.                    #+ENGLISH "CASE clause without objects: ~S"
  7212.                    clause
  7213.           )
  7214.           (let ((keys (car clause)))
  7215.             (if default-passed ; war der Default schon da?
  7216.               (setq keys nil)
  7217.               (if (or (eq keys 'T) (eq keys 'OTHERWISE))
  7218.                 (setq keys 'T default-passed t)
  7219.                 (let ((newkeys '()))
  7220.                   (dolist (key (if (listp keys) keys (list keys)))
  7221.                     (unless (member key allkeys :test #'eq) ; remove-duplicates
  7222.                       (push key allkeys) (push key newkeys)
  7223.                   ) )
  7224.                   (setq keys (nreverse newkeys))
  7225.             ) ) )
  7226.             (push (cons keys (cdr clause)) newclauses)
  7227.       ) ) )
  7228.       (unless default-passed (push '(T NIL) newclauses))
  7229.       (setq newclauses (nreverse newclauses))
  7230.       (setq allkeys (nreverse allkeys))
  7231.     )
  7232.     ; newclauses enthält jetzt keine doppelten keys, genau einmal T als keys,
  7233.     ; und allkeys ist die Menge aller Keys.
  7234.     (if (<= (length allkeys) 2) ; wenige Keys -> direkt EQL verwenden
  7235.       (let ((keyvar (gensym)))
  7236.         (labels ((ifify (clauses)
  7237.                    (if (null clauses)
  7238.                      'NIL
  7239.                      `(IF ,(let ((keys (caar clauses)))
  7240.                              (if (atom keys) ; keys = T, der Default-Fall?
  7241.                                'T
  7242.                                `(OR ,@(mapcar
  7243.                                         #'(lambda (key) `(EQL ,keyvar ',key))
  7244.                                         keys
  7245.                                 )     )
  7246.                            ) )
  7247.                         (PROGN ,@(cdar clauses))
  7248.                         ,(ifify (cdr clauses))
  7249.                       )
  7250.                 )) )
  7251.           (c-form
  7252.             `(LET ((,keyvar ,keyform)) (PROGN ,keyvar ,(ifify newclauses)))
  7253.       ) ) )
  7254.       (let ((keyform-anode (c-form keyform 'ONE))
  7255.             (default-anode nil)
  7256.             (cases '())) ; Liste von Tripeln (keylist label anode)
  7257.         (dolist (clause newclauses)
  7258.           (if (car clause)
  7259.             (let ((anode (c-form `(PROGN ,@(cdr clause)))))
  7260.               (if (atom (car clause))
  7261.                 (setq default-anode anode)
  7262.                 (push (list (car clause) (make-label 'NIL) anode) cases)
  7263.             ) )
  7264.             (let ((*no-code* t)) (c-form `(PROGN ,@(cdr clause)) 'NIL))
  7265.         ) )
  7266.         (setq cases (nreverse cases))
  7267.         (if (anode-constantp keyform-anode)
  7268.           (let ((value (anode-constant-value keyform-anode)))
  7269.             (dolist (case cases default-anode)
  7270.               (when (member value (first case) :test #'eql)
  7271.                 (return (third case))
  7272.           ) ) )
  7273.           (let ((default-label (make-label 'NIL))
  7274.                 (end-label (make-label *for-value*))
  7275.                 (test (if (every #'EQL=EQ allkeys) 'EQ 'EQL)))
  7276.             (make-anode
  7277.               :type 'CASE
  7278.               :sub-anodes `(,keyform-anode ,@(mapcar #'third cases) ,default-anode)
  7279.               :seclass
  7280.                 (anodelist-seclass-or
  7281.                   `(,keyform-anode ,@(mapcar #'third cases) ,default-anode)
  7282.                 )
  7283.               :code
  7284.                 `(,keyform-anode
  7285.                   (JMPHASH
  7286.                     ,test
  7287.                     ,(mapcap ; Aliste (obji -> labeli)
  7288.                        #'(lambda (case)
  7289.                            (let ((label (second case)))
  7290.                              (mapcar #'(lambda (obj) (cons obj label))
  7291.                                      (first case)
  7292.                          ) ) )
  7293.                        cases
  7294.                      )
  7295.                     ,default-label
  7296.                     ,@(mapcar #'second cases) ; alle Labels, ohne Doppelte
  7297.                   )
  7298.                   ,@(mapcap
  7299.                       #'(lambda (case)
  7300.                           `(,(second case) ; Label
  7301.                             ,(third case) ; Anode
  7302.                             (JMP ,end-label)
  7303.                            )
  7304.                         )
  7305.                       cases
  7306.                     )
  7307.                   ,default-label
  7308.                   ,default-anode
  7309.                   ,end-label
  7310.                  )
  7311.           ) )
  7312. ) ) ) ) )
  7313.  
  7314.  
  7315. ;   ERSTER PASS :   I N L I N E - F U N K T I O N E N   (PRIMOPS)
  7316.  
  7317. ; Funktionsaufrufe, die wie special forms behandelt werden:
  7318.  
  7319. ; Erst FUNCALL bzw. SYS::%FUNCALL.
  7320.  
  7321. ; (c-FUNCALL-NOTINLINE funform args) compiliert einen Funktionsaufruf
  7322. ; (SYS::%FUNCALL funform . args),
  7323. ; für den das STACK-Layout der Argumente nicht zur Compile-Zeit bestimmt
  7324. ; werden kann.
  7325. (defun c-FUNCALL-NOTINLINE (funform args)
  7326.   (test-list args 0)
  7327.   (let* ((anode1 (c-form funform 'ONE))
  7328.          (*stackz* (cons 1 *stackz*)))
  7329.     (do ((formlistr args (cdr formlistr))
  7330.          #+COMPILER-DEBUG (anodelist (list anode1))
  7331.          (codelist (list '(FUNCALLP) anode1)))
  7332.         ((null formlistr)
  7333.          (push `(FUNCALL ,(length args)) codelist)
  7334.          (make-anode
  7335.            :type 'FUNCALL
  7336.            :sub-anodes (nreverse anodelist)
  7337.            :seclass '(T . T)
  7338.            :code (nreverse codelist)
  7339.         ))
  7340.       (let ((anode (c-form (car formlistr) 'ONE)))
  7341.         #+COMPILER-DEBUG (push anode anodelist)
  7342.         (push anode codelist)
  7343.       )
  7344.       (push '(PUSH) codelist)
  7345.       (push 1 *stackz*)
  7346. ) ) )
  7347.  
  7348. ; (c-FUNCALL-INLINE funform args applyargs lambdabody sameenv) compiliert einen
  7349. ; Funktionsaufruf (SYS::%FUNCALL funform . args) bzw.
  7350. ; (APPLY funform . args applyargs) [applyargs eine Liste aus einer Form],
  7351. ; für den das STACK-Layout der Argumente zur Compile-Zeit bestimmt werden kann.
  7352. ; sameenv gibt an, ob lambdabody im selben Environment oder im
  7353. ; Top-Level-Environment zu betrachten ist.
  7354. (defun c-FUNCALL-INLINE (funform arglist applyarglist lambdabody sameenv)
  7355.   (test-list lambdabody 1)
  7356.   (multiple-value-bind (reqvar  optvar optinit optsvar  restvar
  7357.                         keyflag keyword keyvar keyinit keysvar allow-other-keys
  7358.                         auxvar auxinit)
  7359.       (analyze-lambdalist (pop lambdabody))
  7360.     (when (or keyflag keyword keyvar keyinit keysvar allow-other-keys)
  7361.       (compiler-error 'c-FUNCALL-INLINE)
  7362.     )
  7363.     (let ((r (length reqvar)) ; Anzahl der required-Argumente
  7364.           (s (length optvar)) ; Anzahl der optionalen Argumente
  7365.           (|t| (length arglist))) ; Anzahl der angegebenen Argumente
  7366.       (when (and (null restvar) (> |t| (+ r s)))
  7367.         ; zu viele Argumente angegeben. Wird beseitigt durch Einführung
  7368.         ; mehrerer zusätzlicher optionaler Argumente:
  7369.         (catch 'c-error
  7370.           (c-error #+DEUTSCH "Zuviele Argumente für ~S"
  7371.                    #+ENGLISH "Too many arguments to ~S"
  7372.                    funform
  7373.         ) )
  7374.         (dotimes (i (- |t| (+ r s)))
  7375.           (let ((var (gensym)))
  7376.             (setq optvar (append optvar (list var)))
  7377.             (setq optinit (append optinit (list nil)))
  7378.             (setq optsvar (append optsvar (list nil)))
  7379.             (incf s)
  7380.             (push `(DECLARE (IGNORE ,var)) lambdabody)
  7381.       ) ) )
  7382.       (when (and (null applyarglist) (< |t| r))
  7383.         ; zu wenige Argumente angegeben. Wird beseitigt durch Einführung
  7384.         ; zusätzlicher Argumente:
  7385.         (catch 'c-error
  7386.           (c-error #+DEUTSCH "Zuwenig Argumente für ~S"
  7387.                    #+ENGLISH "Too few arguments to ~S"
  7388.                    funform
  7389.         ) )
  7390.         (setq arglist (append arglist (make-list (- r |t|) :initial-element nil)))
  7391.         (setq |t| r)
  7392.       )
  7393.       ; Nun ist (t>=r oder apply-arg da) und (t<=r+s oder &rest-Parameter da).
  7394.       (let ((oldstackz *stackz*)
  7395.             (oldvenv *venv*)
  7396.             (oldfenv *fenv*)
  7397.             (oldbenv *benv*)
  7398.             (oldgenv *genv*)
  7399.             (olddenv *denv*)
  7400.             (*stackz* *stackz*)
  7401.             (*venv* (and sameenv *venv*))
  7402.             (*venvc* *venvc*)
  7403.             (*fenv* (and sameenv *fenv*))
  7404.             (*benv* (and sameenv *benv*))
  7405.             (*genv* (and sameenv *genv*))
  7406.             (*denv* (if sameenv
  7407.                       *denv*
  7408.                       (cons `(INLINING ,funform)
  7409.                             (remove-if-not #'(lambda (declspec)
  7410.                                                (case (car declspec)
  7411.                                                  ((DECLARATION SYS::IN-DEFUN INLINING) t)
  7412.                                                  (t nil)
  7413.                                              ) )
  7414.                                            *denv*
  7415.            ))       ) )     )
  7416.         (multiple-value-bind (body-rest declarations)
  7417.             (parse-body lambdabody t (vector *venv* *fenv*))
  7418.           (let (*specials* *ignores* *ignorables*
  7419.                 req-vars req-anodes
  7420.                 opt-vars opt-anodes opts-vars opts-anodes opt-all
  7421.                 rest-vars rest-anodes
  7422.                 fixed-anodes
  7423.                 reqfixed-vars reqfixed-dummys reqfixed-stackzs
  7424.                 optfixed-vars optfixed-dummys optfixed-anodes
  7425.                 optsfixed-vars optsfixed-anodes optfixed-stackzs
  7426.                 restfixed-vars restfixed-dummys restfixed-stackzs
  7427.                 aux-vars aux-anodes
  7428.                 closuredummy-stackz closuredummy-venvc
  7429.                )
  7430.             (multiple-value-setq (*specials* *ignores* *ignorables*)
  7431.               (process-declarations declarations)
  7432.             )
  7433.             ; Special-Variable auf *venv* pushen:
  7434.             (push-specials)
  7435.             (push 0 *stackz*) (push nil *venvc*) ; Platz für Closure-Dummyvar
  7436.             (setq closuredummy-stackz *stackz* closuredummy-venvc *venvc*)
  7437.             (flet ((finish-using-applyarg (reqvar optvar optinit optsvar restvar)
  7438.                      ; reqvar und optvar/optinit/optsvar sowie arglist sind schon
  7439.                      ; teilweise verkürzt. Zerlegen der weiteren Argumentliste
  7440.                      ; mittels UNLIST bzw. UNLIST*. Daher ein Stackaufbau mit
  7441.                      ; festem Aussehen, vgl. c-LAMBDABODY.
  7442.                      (setq fixed-anodes
  7443.                            (list
  7444.                              (let ((anode1 (let ((*venv* oldvenv)
  7445.                                                  (*fenv* oldfenv)
  7446.                                                  (*benv* oldbenv)
  7447.                                                  (*genv* oldgenv)
  7448.                                                  (*denv* olddenv))
  7449.                                              (c-form (first applyarglist) 'ONE)
  7450.                                    )       )
  7451.                                    (anode2 (c-unlist (not (eql restvar 0))
  7452.                                                      (+ (length reqvar) (length optvar))
  7453.                                                      (length optvar)
  7454.                                   ))       )
  7455.                                (make-anode
  7456.                                  :type 'APPLY-UNLIST
  7457.                                  :sub-anodes (list anode1 anode2)
  7458.                                  :seclass (anodes-seclass-or anode1 anode2)
  7459.                                  :code `(,anode1 ,anode2)
  7460.                      )     ) ) )
  7461.                      ; Stack-Dummy-Variable für die reqvar,optvar,restvar bilden:
  7462.                      (multiple-value-setq (reqfixed-vars reqfixed-dummys)
  7463.                        (process-fixed-var-list reqvar)
  7464.                      )
  7465.                      (multiple-value-setq (optfixed-vars optfixed-dummys)
  7466.                        (process-fixed-var-list optvar)
  7467.                      )
  7468.                      (multiple-value-setq (restfixed-vars restfixed-dummys)
  7469.                        (if (eql restvar 0)
  7470.                          (values '() '())
  7471.                          (process-fixed-var-list (list restvar))
  7472.                      ) )
  7473.                      ; Bindungen der required-Parameter aktivieren:
  7474.                      (setq reqfixed-stackzs (bind-req-vars reqfixed-vars))
  7475.                      ; Bindungen der optional-Parameter/svar aktivieren:
  7476.                      (multiple-value-setq (optfixed-anodes optfixed-stackzs optsfixed-vars optsfixed-anodes)
  7477.                        (bind-opt-vars optfixed-vars optfixed-dummys optinit optsvar)
  7478.                      )
  7479.                      ; Bindung des rest-Parameters aktivieren:
  7480.                      (unless (eql restvar 0)
  7481.                        (setq restfixed-stackzs (bind-rest-vars restfixed-vars))
  7482.                      )
  7483.                   ))
  7484.               (block main-args
  7485.                 ; required-Parameter binden:
  7486.                 (do ((reqvarr reqvar (cdr reqvarr)))
  7487.                     ((null reqvarr))
  7488.                   (if (null arglist) ; impliziert, daß apply-arg da
  7489.                     (return-from main-args
  7490.                       (finish-using-applyarg reqvarr optvar optinit optsvar restvar)
  7491.                     )
  7492.                     (let* ((form (pop arglist))
  7493.                            (anode (let ((*venv* oldvenv)
  7494.                                         (*fenv* oldfenv)
  7495.                                         (*benv* oldbenv)
  7496.                                         (*genv* oldgenv)
  7497.                                         (*denv* olddenv))
  7498.                                     (c-form form 'ONE)
  7499.                            )      )
  7500.                            (var (bind-movable-var (car reqvarr) anode)))
  7501.                       (push anode req-anodes)
  7502.                       (push var req-vars)
  7503.                       (push-*venv* var)
  7504.                 ) ) )
  7505.                 ; optionale Parameter und Svars binden:
  7506.                 (do ((optvarr optvar (cdr optvarr))
  7507.                      (optinitr optinit (cdr optinitr))
  7508.                      (optsvarr optsvar (cdr optsvarr)))
  7509.                     ((null optvarr))
  7510.                   (if (and applyarglist (null arglist))
  7511.                     (return-from main-args
  7512.                       (finish-using-applyarg '() optvarr optinitr optsvarr restvar)
  7513.                     )
  7514.                     (let* ((svar-init (not (null arglist))) ; = NIL oder T
  7515.                            (anode (if svar-init
  7516.                                     (progn
  7517.                                       (let ((*no-code* t))
  7518.                                         (c-form (car optinitr) 'NIL)
  7519.                                       )
  7520.                                       (let ((*venv* oldvenv)
  7521.                                             (*fenv* oldfenv)
  7522.                                             (*benv* oldbenv)
  7523.                                             (*genv* oldgenv)
  7524.                                             (*denv* olddenv))
  7525.                                         (c-form (pop arglist) 'ONE)
  7526.                                     ) )
  7527.                                     (c-form (car optinitr) 'ONE)
  7528.                            )      )
  7529.                            (var (bind-movable-var (car optvarr) anode)))
  7530.                       (push anode opt-anodes)
  7531.                       (push var opt-vars)
  7532.                       (push-*venv* var)
  7533.                       (push
  7534.                         (cons (list var anode)
  7535.                           (if (eql (car optsvarr) 0)
  7536.                             nil
  7537.                             (let* ((anode (c-form svar-init 'ONE))
  7538.                                    (var (bind-movable-var (car optsvarr) anode)))
  7539.                               (push anode opts-anodes)
  7540.                               (push var opts-vars)
  7541.                               (push-*venv* var)
  7542.                               (list var anode)
  7543.                         ) ) )
  7544.                         opt-all
  7545.                 ) ) ) )
  7546.                 (if (eql restvar 0)
  7547.                   ; weitere Argumente verbrauchen:
  7548.                   (when applyarglist
  7549.                     (finish-using-applyarg '() '() '() '() restvar)
  7550.                   )
  7551.                   ; Rest-Parameter binden:
  7552.                   (let* ((form (if applyarglist
  7553.                                  (if arglist `(LIST* ,@arglist ,@applyarglist) (first applyarglist))
  7554.                                  (if arglist `(LIST ,@arglist) 'NIL)
  7555.                          )     )
  7556.                          (anode (let ((*venv* oldvenv)
  7557.                                       (*fenv* oldfenv)
  7558.                                       (*benv* oldbenv)
  7559.                                       (*genv* oldgenv)
  7560.                                       (*denv* olddenv))
  7561.                                   (c-form form 'ONE)
  7562.                          )      )
  7563.                          (var (bind-movable-var restvar anode)))
  7564.                     (push anode rest-anodes)
  7565.                     (push var rest-vars)
  7566.                     (push-*venv* var)
  7567.                 ) )
  7568.             ) )
  7569.             (setq req-vars (nreverse req-vars))
  7570.             (setq req-anodes (nreverse req-anodes))
  7571.             (setq opt-vars (nreverse opt-vars))
  7572.             (setq opt-anodes (nreverse opt-anodes))
  7573.             (setq opts-vars (nreverse opts-vars))
  7574.             (setq opts-anodes (nreverse opts-anodes))
  7575.             (setq opt-all (nreverse opt-all))
  7576.             ; Bindungen der Aux-Variablen aktivieren:
  7577.             (multiple-value-setq (aux-vars aux-anodes)
  7578.               (bind-aux-vars auxvar auxinit)
  7579.             )
  7580.             (let* ((body-anode (c-form `(PROGN ,@body-rest)))
  7581.                    ; Überprüfen der Variablen:
  7582.                    (varlist
  7583.                      (append req-vars opt-vars opts-vars rest-vars
  7584.                              reqfixed-vars optfixed-vars optsfixed-vars restfixed-vars
  7585.                              aux-vars
  7586.                    ) )
  7587.                    (closurevars
  7588.                      (append
  7589.                        (checking-movable-var-list req-vars req-anodes)
  7590.                        (checking-movable-var-list opt-vars opt-anodes)
  7591.                        (checking-movable-var-list opts-vars opts-anodes)
  7592.                        (checking-movable-var-list rest-vars rest-anodes)
  7593.                        (checking-fixed-var-list reqfixed-vars)
  7594.                        (checking-fixed-var-list optfixed-vars)
  7595.                        (checking-movable-var-list optsfixed-vars optsfixed-anodes)
  7596.                        (checking-fixed-var-list restfixed-vars)
  7597.                        (checking-movable-var-list aux-vars aux-anodes)
  7598.                    ) )
  7599.                    (codelist
  7600.                      `(,@(c-make-closure closurevars closuredummy-venvc closuredummy-stackz)
  7601.                        ,@(mapcap #'c-bind-movable-var-anode req-vars req-anodes)
  7602.                        ,@(mapcap #'(lambda (opt-both)
  7603.                                      (append (apply #'c-bind-movable-var-anode (car opt-both))
  7604.                                              (if (cdr opt-both)
  7605.                                                (apply #'c-bind-movable-var-anode (cdr opt-both))
  7606.                                                '()
  7607.                                    ) )       )
  7608.                                  opt-all
  7609.                          )
  7610.                        ,@(mapcap #'c-bind-movable-var-anode rest-vars rest-anodes)
  7611.                        ,@fixed-anodes
  7612.                        ,@(mapcap #'c-bind-fixed-var reqfixed-vars reqfixed-dummys reqfixed-stackzs)
  7613.                        ,@(c-bind-with-svars optfixed-vars optfixed-dummys optsfixed-vars optfixed-anodes optsfixed-anodes optfixed-stackzs)
  7614.                        ,@(mapcap #'c-bind-fixed-var restfixed-vars restfixed-dummys restfixed-stackzs)
  7615.                        ,@(mapcap #'c-bind-movable-var-anode aux-vars aux-anodes)
  7616.                        ,body-anode
  7617.                        (UNWIND ,*stackz* ,oldstackz ,*for-value*)
  7618.                    )  )
  7619.                    (anode
  7620.                      (make-anode
  7621.                        :type 'FUNCALL
  7622.                        :sub-anodes
  7623.                          `(,@req-anodes ,@opt-anodes ,@opts-anodes ,@rest-anodes
  7624.                            ,@fixed-anodes ,@optfixed-anodes ,@(remove nil optsfixed-anodes)
  7625.                            ,@aux-anodes ,body-anode
  7626.                           )
  7627.                        :seclass
  7628.                          (seclass-without
  7629.                            (anodelist-seclass-or
  7630.                              `(,@req-anodes ,@opt-anodes ,@opts-anodes ,@rest-anodes
  7631.                                ,@fixed-anodes ,@optfixed-anodes ,@(remove nil optsfixed-anodes)
  7632.                                ,@aux-anodes ,body-anode
  7633.                            )  )
  7634.                            varlist
  7635.                          )
  7636.                        :stackz oldstackz
  7637.                        :code codelist
  7638.                   )) )
  7639.               (when closurevars
  7640.                 (setf (first closuredummy-stackz) 1) ; 1 Stackplatz für Dummy
  7641.                 (setf (first closuredummy-venvc)
  7642.                   (cons closurevars closuredummy-stackz)
  7643.               ) )
  7644.               (optimize-var-list varlist)
  7645.               anode
  7646. ) ) ) ) ) ) )
  7647.  
  7648. ; compiliert (fun {form}*), wobei fun eine lokale Funktion ist.
  7649. ; fdescr die zugehörige Information aus *fenv*.
  7650. (defun c-LOCAL-FUNCTION-CALL (fun fdescr args)
  7651.   ; (test-list args 0) ; das erledigt gleich (test-argument-syntax ...)
  7652.   ; Aufruf-Spezifikation holen:
  7653.   (multiple-value-bind (req opt rest-flag key-flag keylist allow-flag)
  7654.       (fdescr-signature fdescr)
  7655.     (case (test-argument-syntax
  7656.             args nil fun req opt rest-flag key-flag keylist allow-flag
  7657.           )
  7658.       ((NO-KEYS STATIC-KEYS)
  7659.        ; Aufruf INLINE
  7660.        (c-DIRECT-FUNCTION-CALL
  7661.          args nil fun req opt rest-flag key-flag keylist
  7662.          nil ; kein SUBR-, sondern Cclosure-Aufruf
  7663.          (cclosure-call-code-producer fun (car fdescr) req opt rest-flag key-flag keylist)
  7664.       ))
  7665.       (t (c-FUNCALL-NOTINLINE `(FUNCTION ,fun) args))
  7666. ) ) )
  7667.  
  7668. ; (c-FUNCTION-CALL funform arglist) compiliert einen Funktionsaufruf
  7669. ; (SYS::%FUNCALL funform . arglist).
  7670. (defun c-FUNCTION-CALL (funform arglist)
  7671.   (if (inline-callable-function-p funform (length arglist))
  7672.     ; Aufruf eines Lambda-Ausdrucks INLINE möglich
  7673.     (c-FUNCALL-INLINE funform arglist nil (cdr (second funform)) t)
  7674.     (if (and (consp funform) (eq (first funform) 'FUNCTION)
  7675.              ; Ausdrücke der Form (FUNCTION ...) dürfen zu beliebigem
  7676.              ; Zeitpunkt ausgewertet werden, also ist
  7677.              ; (SYS::%FUNCALL (FUNCTION fun) . arglist)  äquivalent zu
  7678.              ; (fun . arglist).
  7679.              (consp (rest funform)) (function-name-p (second funform)) ; vorerst nur #'sym, sonst Endlosschleife!
  7680.         )
  7681.       (progn
  7682.         (test-list funform 2 2)
  7683.         (c-form `(,(second funform) ,@arglist)) ; genauer aufschlüsseln, vgl. c-FUNCTION ??
  7684.       )
  7685.       ; Aufruf NOTINLINE
  7686.       (c-FUNCALL-NOTINLINE funform arglist)
  7687. ) ) )
  7688.  
  7689. (defun c-FUNCALL ()
  7690.   (test-list *form* 2)
  7691.   (c-FUNCTION-CALL (second *form*) (cddr *form*))
  7692. )
  7693.  
  7694. (defun c-APPLY ()
  7695.   (test-list *form* 3)
  7696.   (let* ((funform (second *form*))
  7697.          (arglist (cddr *form*))
  7698.          (n (1- (length arglist)))) ; Mindestanzahl Argumente
  7699.     (if (inline-callable-function-p funform n t)
  7700.       ; Aufruf eines Lambda-Ausdrucks INLINE möglich
  7701.       (return-from c-APPLY
  7702.         (c-FUNCALL-INLINE funform (butlast arglist) (last arglist) (cdr (second funform)) t)
  7703.       )
  7704.       (when (and (consp funform) (eq (first funform) 'FUNCTION)
  7705.                  ; Ausdrücke der Form (FUNCTION ...) dürfen zu beliebigem
  7706.                  ; Zeitpunkt ausgewertet werden.
  7707.                  (consp (rest funform)) (function-name-p (second funform))
  7708.             )
  7709.         (let ((fun (second funform)))
  7710.           (test-list funform 2 2)
  7711.           (unless (declared-notinline fun) ; darf fun INLINE genommen werden?
  7712.             (flet ((c-LOCAL-APPLY (fdescr)
  7713.                      (multiple-value-bind (req opt rest-flag key-flag keylist allow-flag)
  7714.                          (fdescr-signature fdescr)
  7715.                        (unless key-flag
  7716.                          ; ohne Keyword-Argumente
  7717.                          (when (eq (test-argument-syntax (butlast arglist) (last arglist)
  7718.                                      fun req opt rest-flag key-flag keylist allow-flag
  7719.                                    )
  7720.                                  'NO-KEYS
  7721.                                )
  7722.                            ; Syntax stimmt -> Aufruf INLINE
  7723.                            (return-from c-APPLY
  7724.                              (c-DIRECT-FUNCTION-CALL (butlast arglist) (last arglist)
  7725.                                fun req opt rest-flag key-flag keylist
  7726.                                nil ; kein SUBR-, sondern Cclosure-Aufruf
  7727.                                (cclosure-call-code-producer fun (car fdescr) req opt rest-flag key-flag keylist)
  7728.                   )) ) ) ) ) )
  7729.               (multiple-value-bind (a b c) (fenv-search fun)
  7730.                 (declare (ignore b))
  7731.                 ; (APPLY #'fun . args) kann evtl. vereinfacht werden
  7732.                 (case a
  7733.                   ((NIL) ; globale Funktion
  7734.                     (unless (and (symbolp fun) (or (special-form-p fun) (macro-function fun))) ; Special-Form oder globaler Macro ?
  7735.                       (when (and (equal fun (fnode-name *func*))
  7736.                                  (member `(SYS::IN-DEFUN ,fun) *denv* :test #'equal)
  7737.                             )
  7738.                         ; rekursiver Aufruf der aktuellen globalen Funktion
  7739.                         (c-LOCAL-APPLY (cons *func* nil))
  7740.                       )
  7741.                       (let ((inline-lambdabody
  7742.                               (or (and *compiling-from-file*
  7743.                                        (cdr (assoc fun *inline-definitions* :test #'equal))
  7744.                                   )
  7745.                                   (get (get-funname-symbol fun) 'sys::inline-expansion)
  7746.                            )) )
  7747.                         (if (and #| inline-lambdabody |#
  7748.                                  (consp inline-lambdabody)
  7749.                                  (inline-callable-function-p `(FUNCTION (LAMBDA ,@inline-lambdabody)) n t)
  7750.                             )
  7751.                           ; Aufruf einer globalen Funktion INLINE möglich
  7752.                           (return-from c-APPLY
  7753.                             (c-FUNCALL-INLINE fun (butlast arglist) (last arglist) inline-lambdabody nil)
  7754.                   ) ) ) ) )
  7755.                   (LOCAL ; lokale Funktion
  7756.                     (c-LOCAL-APPLY c)
  7757.                 ) )
  7758.       ) ) ) ) )
  7759.     )
  7760.     ; Wenn keine der Optimierungen möglich war:
  7761.     (let* ((anode1 (c-form funform 'ONE))
  7762.            (*stackz* (cons 1 *stackz*)))
  7763.       (do ((formlistr arglist (cdr formlistr))
  7764.            #+COMPILER-DEBUG (anodelist (list anode1))
  7765.            (codelist (list '(APPLYP) anode1)))
  7766.           ((null formlistr)
  7767.            (push `(APPLY ,n) codelist)
  7768.            (make-anode
  7769.              :type 'APPLY
  7770.              :sub-anodes (nreverse anodelist)
  7771.              :seclass '(T . T)
  7772.              :code (nreverse codelist)
  7773.           ))
  7774.         (let ((anode (c-form (car formlistr) 'ONE)))
  7775.           #+COMPILER-DEBUG (push anode anodelist)
  7776.           (push anode codelist)
  7777.           (when (cdr formlistr)
  7778.             (push 1 *stackz*) (push '(PUSH) codelist)
  7779.     ) ) ) )
  7780. ) )
  7781.  
  7782. (defun c-PLUS ()
  7783.   (test-list *form* 1)
  7784.   ; bilde Teilsumme der konstanten Argumente, Rest dann dazu:
  7785.   (let ((const-sum 0)
  7786.         (other-parts '())
  7787.         val
  7788.        )
  7789.     (dolist (form (cdr *form*))
  7790.       (if (and (c-constantp form) (numberp (setq val (c-constant-value form))))
  7791.         (setq const-sum (+ const-sum val))
  7792.         (push form other-parts)
  7793.     ) )
  7794.     (case (length other-parts)
  7795.       (0 ; nur konstante Summanden
  7796.          (c-form const-sum) ; Zahl const-sum wertet zu sich selbst aus
  7797.       )
  7798.       (1 ; nur ein variabler Summand
  7799.          (case const-sum
  7800.            (0 (c-form (first other-parts))) ; keine Addition nötig
  7801.            (+1 (c-form `(1+ ,(first other-parts))))
  7802.            (-1 (c-form `(1- ,(first other-parts))))
  7803.            (t (c-GLOBAL-FUNCTION-CALL-form `(+ ,const-sum ,@other-parts)))
  7804.       )  )
  7805.       (t (setq other-parts (nreverse other-parts))
  7806.          (unless (eql const-sum 0) (push const-sum other-parts))
  7807.          (c-GLOBAL-FUNCTION-CALL-form `(+ ,@other-parts))
  7808. ) ) ) )
  7809.  
  7810. (defun c-MINUS ()
  7811.   (test-list *form* 2)
  7812.   (let ((unary-p (= (length *form*) 2)) ; unäres Minus oder nicht?
  7813.         (const-sum 0) ; Summe der konstanten Teile
  7814.         (first-part 0) ; zu addierende Form
  7815.         (other-parts '()) ; abzuziehende Formen
  7816.         val
  7817.        )
  7818.     (unless unary-p
  7819.       (let ((form (second *form*)))
  7820.         (if (and (c-constantp form) (numberp (setq val (c-constant-value form))))
  7821.           (setq const-sum val)
  7822.           (setq first-part form)
  7823.     ) ) )
  7824.     (dolist (form (if unary-p (cdr *form*) (cddr *form*)))
  7825.       (if (and (c-constantp form) (numberp (setq val (c-constant-value form))))
  7826.         (setq const-sum (- const-sum val))
  7827.         (push form other-parts)
  7828.     ) )
  7829.     (if (null other-parts)
  7830.       ; nichts zu subtrahieren
  7831.       (let ((*form* `(+ ,const-sum ,first-part))) (c-PLUS))
  7832.       ; etwas zu subtrahieren
  7833.       (c-GLOBAL-FUNCTION-CALL-form
  7834.         `(-
  7835.           ,@(if (eql first-part 0) ; variable zu addierende Form?
  7836.               (if (and (eql const-sum 0) (null (cdr other-parts)))
  7837.                 '()
  7838.                 `(,const-sum)
  7839.               )
  7840.               (if (eql const-sum 0)
  7841.                 `(,first-part)
  7842.                 `(,first-part ,(- const-sum))
  7843.             ) )
  7844.           ,@(nreverse other-parts)
  7845.          )
  7846. ) ) ) )
  7847.  
  7848. (defun c-SVSTORE ()
  7849.   (test-list *form* 4 4)
  7850.   ; (sys::svstore arg1 arg2 arg3) -> (sys::%svstore arg3 arg1 arg2)
  7851.   (let ((arg1 (second *form*)) (arg2 (third *form*)) (arg3 (fourth *form*))
  7852.         (argvar1 (gensym)) (argvar2 (gensym)))
  7853.     (c-form
  7854.       `(LET* ((,argvar1 ,arg1) (,argvar2 ,arg2))
  7855.          (sys::%svstore ,arg3 ,argvar1 ,argvar2)
  7856.        )
  7857. ) ) )
  7858.  
  7859. (defun c-EQ ()
  7860.   (test-list *form* 3 3)
  7861.   (let ((arg1 (second *form*)) (arg2 (third *form*)))
  7862.     (if (and (c-constantp arg1) (c-constantp arg2))
  7863.       (c-form `(QUOTE ,(eq (c-constant-value arg1) (c-constant-value arg2))))
  7864.       (progn
  7865.         (when (c-constantp arg1)
  7866.           (rotatef arg1 arg2) ; Besser arg2 konstant, damit JMPIFEQTO geht
  7867.         )
  7868.         (if (and (c-constantp arg2) (eq (c-constant-value arg2) 'NIL))
  7869.           (c-GLOBAL-FUNCTION-CALL-form `(NULL ,arg1))
  7870.           (c-GLOBAL-FUNCTION-CALL-form `(EQ ,arg1 ,arg2))
  7871. ) ) ) ) )
  7872.  
  7873. ; bei Symbolen, Fixnums und Characters ist EQL mit EQ gleichbedeutend
  7874. (defun EQL=EQ (x) (or (symbolp x) (fixnump x) (characterp x)))
  7875.  
  7876. (defun c-EQL ()
  7877.   (test-list *form* 3 3)
  7878.   (let ((arg1 (second *form*)) (arg2 (third *form*)))
  7879.     (cond ((and (c-constantp arg1) (c-constantp arg2))
  7880.            (c-form `(QUOTE ,(eql (c-constant-value arg1) (c-constant-value arg2))))
  7881.           )
  7882.           ((or (and (c-constantp arg1) (EQL=EQ (c-constant-value arg1)))
  7883.                (and (c-constantp arg2) (EQL=EQ (c-constant-value arg2)))
  7884.            )
  7885.            (let ((*form* `(EQ ,arg1 ,arg2))) (c-EQ))
  7886.           )
  7887.           (t (c-GLOBAL-FUNCTION-CALL 'EQL))
  7888. ) ) )
  7889.  
  7890. ; bei Symbolen, Zahlen und Characters ist EQUAL mit EQL gleichbedeutend
  7891. (defun EQUAL=EQL (x) (or (symbolp x) (numberp x) (characterp x)))
  7892.  
  7893. (defun c-EQUAL ()
  7894.   (test-list *form* 3 3)
  7895.   (let ((arg1 (second *form*)) (arg2 (third *form*)))
  7896.     (cond ((or (and (c-constantp arg1) (EQUAL=EQL (c-constant-value arg1)))
  7897.                (and (c-constantp arg2) (EQUAL=EQL (c-constant-value arg2)))
  7898.            )
  7899.            (let ((*form* `(EQL ,arg1 ,arg2))) (c-EQL))
  7900.           )
  7901.           (t (c-GLOBAL-FUNCTION-CALL 'EQUAL))
  7902. ) ) )
  7903.  
  7904. ; Bildet den inneren Teil einer MAPCAR/MAPC/MAPCAN/MAPCAP-Expansion
  7905. (defun c-MAP-on-CARs-inner (innerst-fun blockname restvars &optional (itemvars '()))
  7906.   (if (null restvars)
  7907.     (funcall innerst-fun (nreverse itemvars))
  7908.     (let ((restvar (car restvars))
  7909.           (itemvar (gensym)))
  7910.       `(IF (CONSP ,restvar)
  7911.          (LET ((,itemvar (CAR ,restvar)))
  7912.            ,(c-MAP-on-CARs-inner innerst-fun blockname (cdr restvars) (cons itemvar itemvars))
  7913.          )
  7914.          (RETURN-FROM ,blockname)
  7915. ) ) )  )
  7916.  
  7917. ; Bildet eine MAPCAR/MAPCAN/MAPCAP-Expansion
  7918. (defun c-MAP-on-CARs (adjoin-fun funform forms)
  7919.   (let ((erg (gensym))
  7920.         (blockname (gensym))
  7921.         (restvars
  7922.           (mapcar #'(lambda (form) (declare (ignore form)) (gensym)) forms)
  7923.         )
  7924.         (tag (gensym)))
  7925.     `(LET ((,erg NIL))
  7926.        (BLOCK ,blockname
  7927.          (LET* ,(mapcar #'list restvars forms)
  7928.            (TAGBODY ,tag
  7929.              ,(c-MAP-on-CARs-inner
  7930.                 #'(lambda (itemvars)
  7931.                     `(SETQ ,erg (,adjoin-fun (SYS::%FUNCALL ,funform ,@itemvars) ,erg))
  7932.                   )
  7933.                 blockname
  7934.                 restvars
  7935.               )
  7936.              (SETQ ,@(mapcap #'(lambda (restvar)
  7937.                                  `(,restvar (CDR ,restvar))
  7938.                                )
  7939.                              restvars
  7940.              )       )
  7941.              (GO ,tag)
  7942.        ) ) )
  7943.        (SYS::LIST-NREVERSE ,erg)
  7944. ) )  )
  7945.  
  7946. ; Bildet eine MAPLIST/MAPCON/MAPLAP-Expansion
  7947. (defun c-MAP-on-LISTs (adjoin-fun funform forms)
  7948.   (let ((erg (gensym))
  7949.         (blockname (gensym))
  7950.         (restvars
  7951.           (mapcar #'(lambda (form) (declare (ignore form)) (gensym)) forms)
  7952.         )
  7953.         (tag (gensym)))
  7954.     `(LET ((,erg NIL))
  7955.        (BLOCK ,blockname
  7956.          (LET* ,(mapcar #'list restvars forms)
  7957.            (TAGBODY ,tag
  7958.              (IF (OR ,@(mapcar #'(lambda (restvar) `(ATOM ,restvar)) restvars))
  7959.                (RETURN-FROM ,blockname)
  7960.              )
  7961.              (SETQ ,erg (,adjoin-fun (SYS::%FUNCALL ,funform ,@restvars) ,erg))
  7962.              (SETQ ,@(mapcap #'(lambda (restvar)
  7963.                                  `(,restvar (CDR ,restvar))
  7964.                                )
  7965.                              restvars
  7966.              )       )
  7967.              (GO ,tag)
  7968.        ) ) )
  7969.        (SYS::LIST-NREVERSE ,erg)
  7970. ) )  )
  7971.  
  7972. (defun c-MAPC ()
  7973.   (test-list *form* 3)
  7974.   (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  7975.     (c-form
  7976.       (let* ((tempvar (gensym))
  7977.              (forms (cons tempvar (cdddr *form*)))
  7978.              (blockname (gensym))
  7979.              (restvars
  7980.                (mapcar #'(lambda (form) (declare (ignore form)) (gensym)) forms)
  7981.              )
  7982.              (tag (gensym)))
  7983.         `(LET ((,tempvar ,(third *form*)))
  7984.            (BLOCK ,blockname
  7985.              (LET* ,(mapcar #'list restvars forms)
  7986.                (TAGBODY ,tag
  7987.                  ,(c-MAP-on-CARs-inner
  7988.                     #'(lambda (itemvars) `(SYS::%FUNCALL ,(second *form*) ,@itemvars))
  7989.                     blockname
  7990.                     restvars
  7991.                   )
  7992.                  (SETQ ,@(mapcap #'(lambda (restvar)
  7993.                                      `(,restvar (CDR ,restvar))
  7994.                                    )
  7995.                                  restvars
  7996.                  )       )
  7997.                  (GO ,tag)
  7998.            ) ) )
  7999.            ,tempvar
  8000.     ) )  )
  8001.     (c-GLOBAL-FUNCTION-CALL 'MAPC)
  8002. ) )
  8003.  
  8004. (defun c-MAPL ()
  8005.   (test-list *form* 3)
  8006.   (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8007.     (c-form
  8008.       (let* ((tempvar (gensym))
  8009.              (forms (cons tempvar (cdddr *form*)))
  8010.              (blockname (gensym))
  8011.              (restvars
  8012.                (mapcar #'(lambda (form) (declare (ignore form)) (gensym)) forms)
  8013.              )
  8014.              (tag (gensym)))
  8015.         `(LET ((,tempvar ,(third *form*)))
  8016.            (BLOCK ,blockname
  8017.              (LET* ,(mapcar #'list restvars forms)
  8018.                (TAGBODY ,tag
  8019.                  (IF (OR ,@(mapcar #'(lambda (restvar) `(ATOM ,restvar)) restvars))
  8020.                    (RETURN-FROM ,blockname)
  8021.                  )
  8022.                  (SYS::%FUNCALL ,(second *form*) ,@restvars)
  8023.                  (SETQ ,@(mapcap #'(lambda (restvar)
  8024.                                      `(,restvar (CDR ,restvar))
  8025.                                    )
  8026.                                  restvars
  8027.                  )       )
  8028.                  (GO ,tag)
  8029.            ) ) )
  8030.            ,tempvar
  8031.     ) )  )
  8032.     (c-GLOBAL-FUNCTION-CALL 'MAPL)
  8033. ) )
  8034.  
  8035. (defun c-MAPCAR ()
  8036.   (test-list *form* 3)
  8037.   (if (null *for-value*)
  8038.     (let ((*form* `(MAPC ,@(cdr *form*)))) (c-MAPC))
  8039.     (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8040.       (c-form (c-MAP-on-CARs 'CONS (second *form*) (cddr *form*)))
  8041.       (c-GLOBAL-FUNCTION-CALL 'MAPCAR)
  8042. ) ) )
  8043.  
  8044. (defun c-MAPLIST ()
  8045.   (test-list *form* 3)
  8046.   (if (null *for-value*)
  8047.     (let ((*form* `(MAPL ,@(cdr *form*)))) (c-MAPL))
  8048.     (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8049.       (c-form (c-MAP-on-LISTs 'CONS (second *form*) (cddr *form*)))
  8050.       (c-GLOBAL-FUNCTION-CALL 'MAPLIST)
  8051. ) ) )
  8052.  
  8053. (defun c-MAPCAN ()
  8054.   (test-list *form* 3)
  8055.   (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8056.     (c-form (c-MAP-on-CARs 'NRECONC (second *form*) (cddr *form*)))
  8057.     (c-GLOBAL-FUNCTION-CALL 'MAPCAN)
  8058. ) )
  8059.  
  8060. (defun c-MAPCON ()
  8061.   (test-list *form* 3)
  8062.   (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8063.     (c-form (c-MAP-on-LISTs 'NRECONC (second *form*) (cddr *form*)))
  8064.     (c-GLOBAL-FUNCTION-CALL 'MAPCON)
  8065. ) )
  8066.  
  8067. (defun c-MAPCAP ()
  8068.   (test-list *form* 3)
  8069.   (if (null *for-value*)
  8070.     (let ((*form* `(MAPC ,@(cdr *form*)))) (c-MAPC))
  8071.     (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8072.       (c-form (c-MAP-on-CARs 'REVAPPEND (second *form*) (cddr *form*)))
  8073.       (c-GLOBAL-FUNCTION-CALL 'MAPCAP)
  8074. ) ) )
  8075.  
  8076. (defun c-MAPLAP ()
  8077.   (test-list *form* 3)
  8078.   (if (null *for-value*)
  8079.     (let ((*form* `(MAPL ,@(cdr *form*)))) (c-MAPL))
  8080.     (if (inline-callable-function-p (second *form*) (length (cddr *form*)))
  8081.       (c-form (c-MAP-on-LISTs 'REVAPPEND (second *form*) (cddr *form*)))
  8082.       (c-GLOBAL-FUNCTION-CALL 'MAPLAP)
  8083. ) ) )
  8084.  
  8085. ;; c-TYPEP vgl. TYPEP in type.lsp
  8086. ; Symbole mit Property TYPE-SYMBOL:
  8087. (defconstant c-typep-alist1
  8088.   '((ARRAY . arrayp)
  8089.     (ATOM . atom)
  8090.     (BIT-VECTOR . bit-vector-p)
  8091.     (CHARACTER . characterp)
  8092.     (COMMON . commonp)
  8093.     (COMPILED-FUNCTION . compiled-function-p)
  8094.     (COMPLEX . complexp)
  8095.     (CONS . consp)
  8096.     (DOUBLE-FLOAT . double-float-p)
  8097.     (FIXNUM . fixnump)
  8098.     (FLOAT . floatp)
  8099.     (FUNCTION . functionp)
  8100.     (HASH-TABLE . hash-table-p)
  8101.     (INTEGER . integerp)
  8102.     (KEYWORD . keywordp)
  8103.     (LIST . listp)
  8104.     (LONG-FLOAT . long-float-p)
  8105.     (NULL . null)
  8106.     (NUMBER . numberp)
  8107.     (PACKAGE . packagep)
  8108.     (PATHNAME . pathnamep)
  8109.     (RANDOM-STATE . random-state-p)
  8110.     (RATIONAL . rationalp)
  8111.     (READTABLE . readtablep)
  8112.     (REAL . realp)
  8113.     (SEQUENCE . sys::sequencep)
  8114.     (SHORT-FLOAT . short-float-p)
  8115.     (SIMPLE-ARRAY . sys::simple-array-p)
  8116.     (SIMPLE-BIT-VECTOR . simple-bit-vector-p)
  8117.     (SIMPLE-STRING . simple-string-p)
  8118.     (SIMPLE-VECTOR . simple-vector-p)
  8119.     (SINGLE-FLOAT . single-float-p)
  8120.     (CLOS:STANDARD-GENERIC-FUNCTION . clos::generic-function-p)
  8121.     (CLOS:STANDARD-OBJECT . clos::std-instance-p)
  8122.     (STREAM . streamp)
  8123.     (STRING . stringp)
  8124.     (SYMBOL . symbolp)
  8125.     (VECTOR . vectorp)
  8126. )  )
  8127. (defconstant c-typep-alist2
  8128.   '((BIGNUM . ((x) (and (integerp x) (not (fixnump x)))))
  8129.     (BIT . ((x) (or (eql x 0) (eql x 1))))
  8130.     (NIL . ((x) (declare (ignore x)) nil))
  8131.     (RATIO . ((x) (and (rationalp x) (not (integerp x)))))
  8132.     (STANDARD-CHAR . ((x) (and (characterp x) (standard-char-p x))))
  8133.     (STRING-CHAR . ((x) (and (characterp x) (string-char-p x))))
  8134.     (STRUCTURE .
  8135.       ((x)
  8136.         (let ((y (type-of x)))
  8137.           (and (symbolp y) (get y 'SYS::DEFSTRUCT-DESCRIPTION)
  8138.                (SYS::%STRUCTURE-TYPE-P y x)
  8139.     ) ) ) )
  8140.     (T . ((x) (declare (ignore x)) t))
  8141. )  )
  8142. (defun c-typep-array (tester)
  8143.   #'(lambda (x &optional (el-type '*) (dims '*) &rest illegal-args)
  8144.       (declare (ignore illegal-args))
  8145.       `(AND (,tester ,x)
  8146.             ,@(if (eq el-type '*)
  8147.                 '()
  8148.                 `((EQUAL (ARRAY-ELEMENT-TYPE ,x) ',(upgraded-array-element-type el-type)))
  8149.               )
  8150.             ,@(if (eq dims '*)
  8151.                 '()
  8152.                 (if (numberp dims)
  8153.                   `((EQL ,dims (ARRAY-RANK ,x)))
  8154.                   `((EQL ,(length dims) (ARRAY-RANK ,x))
  8155.                     ,@(let ((i 0))
  8156.                         (mapcap #'(lambda (dim)
  8157.                                     (prog1
  8158.                                       (if (eq dim '*)
  8159.                                         '()
  8160.                                         `((EQL ',dim (ARRAY-DIMENSION ,x ,i)))
  8161.                                       )
  8162.                                       (incf i)
  8163.                                   ) )
  8164.                                 dims
  8165.                       ) )
  8166.                    )
  8167.               ) )
  8168.        )
  8169. )   )
  8170. (defun c-typep-vector (tester)
  8171.   #'(lambda (x &optional (size '*) &rest illegal-args)
  8172.       (declare (ignore illegal-args))
  8173.       `(AND (,tester ,x)
  8174.             ,@(if (eq size '*)
  8175.                 '()
  8176.                 `((EQL (ARRAY-DIMENSION ,x 0) ',size))
  8177.               )
  8178.        )
  8179.     )
  8180. )
  8181. (defun c-typep-number (caller tester)
  8182.   #'(lambda (x &optional (low '*) (high '*) &rest illegal-args)
  8183.       (declare (ignore illegal-args))
  8184.       `(AND (,tester ,x)
  8185.             ,@(cond ((eq low '*) '())
  8186.                     ((funcall tester low) `((<= ,low ,x)))
  8187.                     ((and (consp low) (null (rest low)) (funcall tester (first low)))
  8188.                      `((< ,(first low) ,x))
  8189.                     )
  8190.                     (t (c-warn #+DEUTSCH "~S: Argument zu ~S muß *, ~S oder eine Liste von ~S sein: ~S"
  8191.                                #+ENGLISH "~S: argument to ~S must be *, ~S or a list of ~S: ~S"
  8192.                                #+FRANCAIS "~S : L'argument de ~S doit être *, ~S ou une liste de ~S: ~S"
  8193.                                'typep caller caller caller low
  8194.                        )
  8195.                        (throw 'c-TYPEP nil)
  8196.               )     )
  8197.             ,@(cond ((eq high '*) '())
  8198.                     ((funcall tester high) `((>= ,high ,x)))
  8199.                     ((and (consp high) (null (rest high)) (funcall tester (first high)))
  8200.                      `((> ,(first high) ,x))
  8201.                     )
  8202.                     (t (c-warn #+DEUTSCH "~S: Argument zu ~S muß *, ~S oder eine Liste von ~S sein: ~S"
  8203.                                #+ENGLISH "~S: argument to ~S must be *, ~S or a list of ~S: ~S"
  8204.                                #+FRANCAIS "~S : L'argument de ~S doit être *, ~S ou une liste de ~S: ~S"
  8205.                                'typep caller caller caller high
  8206.                        )
  8207.                        (throw 'c-TYPEP nil)
  8208.               )     )
  8209.        )
  8210.     )
  8211. )
  8212. (defconstant c-typep-alist3
  8213.   `((ARRAY . ,(c-typep-array 'ARRAYP))
  8214.     (SIMPLE-ARRAY . ,(c-typep-array 'SIMPLE-ARRAY-P))
  8215.     (VECTOR .
  8216.       ,#'(lambda (x &optional (el-type '*) (size '*) &rest illegal-args)
  8217.            (declare (ignore illegal-args))
  8218.            `(AND (VECTORP ,x)
  8219.                  ,@(if (eq el-type '*)
  8220.                      '()
  8221.                      `((EQUAL (ARRAY-ELEMENT-TYPE ,x) ',(upgraded-array-element-type el-type)))
  8222.                    )
  8223.                  ,@(if (eq size '*)
  8224.                      '()
  8225.                      `((EQL (ARRAY-DIMENSION ,x 0) ',size))
  8226.                    )
  8227.             )
  8228.          )
  8229.     )
  8230.     (SIMPLE-VECTOR . ,(c-typep-vector 'SIMPLE-VECTOR-P))
  8231.     (COMPLEX .
  8232.       ,#'(lambda (x &optional (rtype '*) (itype rtype) &rest illegal-args)
  8233.            (declare (ignore illegal-args))
  8234.            `(AND (COMPLEXP ,x)
  8235.                  ,@(if (eq rtype '*)
  8236.                      '()
  8237.                      `((TYPEP (REALPART ,x) ',rtype))
  8238.                    )
  8239.                  ,@(if (eq itype '*)
  8240.                      '()
  8241.                      `((TYPEP (IMAGPART ,x) ',itype))
  8242.                    )
  8243.             )
  8244.          )
  8245.     )
  8246.     (INTEGER . ,(c-typep-number 'INTEGER 'INTEGERP))
  8247.     (MOD .
  8248.       ,#'(lambda (x &optional n &rest illegal-args)
  8249.            (declare (ignore illegal-args))
  8250.            (unless (integerp n)
  8251.              (c-warn #+DEUTSCH "~S: Argument zu MOD muß ganze Zahl sein: ~S"
  8252.                      #+ENGLISH "~S: argument to MOD must be an integer: ~S"
  8253.                      #+FRANCAIS "~S : L'argument de MOD doit être un entier: ~S"
  8254.                      'typep n
  8255.              )
  8256.              (throw 'c-TYPEP nil)
  8257.            )
  8258.            `(AND (INTEGERP ,x) (NOT (MINUSP ,x)) (< ,x ,n))
  8259.          )
  8260.     )
  8261.     (SIGNED-BYTE .
  8262.       ,#'(lambda (x &optional (n '*) &rest illegal-args)
  8263.            (declare (ignore illegal-args))
  8264.            (unless (or (eq n '*) (integerp n))
  8265.              (c-warn #+DEUTSCH "~S: Argument zu SIGNED-BYTE muß ganze Zahl oder * sein: ~S"
  8266.                      #+ENGLISH "~S: argument to SIGNED-BYTE must be an integer or * : ~S"
  8267.                      #+FRANCAIS "~S : L'argument de SIGNED-BYTE doit être un entier ou bien * : ~S"
  8268.                      'typep n
  8269.              )
  8270.              (throw 'c-TYPEP nil)
  8271.            )
  8272.            `(AND (INTEGERP ,x)
  8273.                  ,@(if (eq n '*) '() `((< (INTEGER-LENGTH ,x) ,n)))
  8274.             )
  8275.          )
  8276.     )
  8277.     (UNSIGNED-BYTE .
  8278.       ,#'(lambda (x &optional (n '*) &rest illegal-args)
  8279.            (declare (ignore illegal-args))
  8280.            (unless (or (eq n '*) (integerp n))
  8281.              (c-warn #+DEUTSCH "~S: Argument zu UNSIGNED-BYTE muß ganze Zahl oder * sein: ~S"
  8282.                      #+ENGLISH "~S: argument to UNSIGNED-BYTE must be an integer or * : ~S"
  8283.                      #+FRANCAIS "~S : L'argument de UNSIGNED-BYTE doit être un entier ou bien * : ~S"
  8284.                      'typep n
  8285.              )
  8286.              (throw 'c-TYPEP nil)
  8287.            )
  8288.            `(AND (INTEGERP ,x) (NOT (MINUSP ,x))
  8289.                  ,@(if (eq n '*) '() `((<= (INTEGER-LENGTH ,x) ,n)))
  8290.             )
  8291.          )
  8292.     )
  8293.     (REAL . ,(c-typep-number 'REAL 'REALP))
  8294.     (RATIONAL . ,(c-typep-number 'RATIONAL 'RATIONALP))
  8295.     (FLOAT . ,(c-typep-number 'FLOAT 'FLOATP))
  8296.     (SHORT-FLOAT . ,(c-typep-number 'SHORT-FLOAT 'SHORT-FLOAT-P))
  8297.     (SINGLE-FLOAT . ,(c-typep-number 'SINGLE-FLOAT 'SINGLE-FLOAT-P))
  8298.     (DOUBLE-FLOAT . ,(c-typep-number 'DOUBLE-FLOAT 'DOUBLE-FLOAT-P))
  8299.     (LONG-FLOAT . ,(c-typep-number 'LONG-FLOAT 'LONG-FLOAT-P))
  8300.     (STRING . ,(c-typep-vector 'STRINGP))
  8301.     (SIMPLE-STRING . ,(c-typep-vector 'SIMPLE-STRING-P))
  8302.     (BIT-VECTOR . ,(c-typep-vector 'BIT-VECTOR-P))
  8303.     (SIMPLE-BIT-VECTOR . ,(c-typep-vector 'SIMPLE-BIT-VECTOR-P))
  8304. )  )
  8305. (defun c-TYPEP () ; vgl. TYPEP in type.lsp
  8306.   (test-list *form* 3 3)
  8307.   (let ((objform (second *form*))
  8308.         (typeform (third *form*)))
  8309.     (when (c-constantp typeform)
  8310.       (let ((type (c-constant-value typeform)) h)
  8311.         (cond ((symbolp type)
  8312.                 (cond ; Test auf Property TYPE-SYMBOL:
  8313.                       ((setq h (assoc type c-typep-alist1))
  8314.                         (setq h (cdr h))
  8315.                         (return-from c-TYPEP
  8316.                           (c-GLOBAL-FUNCTION-CALL-form `(,h ,objform))
  8317.                       ) )
  8318.                       ((setq h (assoc type c-typep-alist2))
  8319.                         (setq h (cdr h))
  8320.                         (return-from c-TYPEP
  8321.                           (let ((*form* `(,h ,objform)))
  8322.                             (c-FUNCALL-INLINE
  8323.                               (symbol-suffix '#:TYPEP (symbol-name type))
  8324.                               (list objform)
  8325.                               nil
  8326.                               h
  8327.                               nil
  8328.                       ) ) ) )
  8329.                       ; Test auf Property TYPE-LIST:
  8330.                       ((setq h (assoc type c-typep-alist3))
  8331.                         (setq h (cdr h))
  8332.                         (let* ((objvar (gensym))
  8333.                                (testform (funcall h objvar))
  8334.                                (lambdabody `((,objvar) ,testform)))
  8335.                           (return-from c-TYPEP
  8336.                             (let ((*form* `((lambda ,@lambdabody) ,objform)))
  8337.                               (c-FUNCALL-INLINE
  8338.                                 (symbol-suffix '#:TYPEP (symbol-name type))
  8339.                                 (list objform)
  8340.                                 nil
  8341.                                 lambdabody
  8342.                                 nil
  8343.                       ) ) ) ) )
  8344.                       #+CLISP ; Test auf Property DEFTYPE-EXPANDER:
  8345.                       ((setq h (get type 'SYS::DEFTYPE-EXPANDER))
  8346.                         (return-from c-TYPEP
  8347.                           (c-form `(TYPEP ,objform ',(funcall h (list type))))
  8348.                       ) )
  8349.                       #+CLISP ; Test auf Property DEFSTRUCT-DESCRIPTION:
  8350.                       ((get type 'SYS::DEFSTRUCT-DESCRIPTION)
  8351.                         (return-from c-TYPEP
  8352.                           (c-form `(SYS::%STRUCTURE-TYPE-P ',type ,objform))
  8353.                       ) )
  8354.                       #+CLISP ; Test auf Property CLOS::CLASS:
  8355.                       ((and (setq h (get type 'CLOS::CLASS)) (clos::class-p h)
  8356.                             (eq (clos:class-name h) type)
  8357.                        )
  8358.                         (return-from c-TYPEP
  8359.                           (c-form `(CLOS::SUBCLASSP (CLOS:CLASS-OF ,objform)
  8360.                                      (LOAD-TIME-VALUE (CLOS:FIND-CLASS ',type))
  8361.                                    )
  8362.                       ) ) )
  8363.               ) )
  8364.               ((and (consp type) (symbolp (first type)))
  8365.                 (catch 'c-TYPEP
  8366.                   (cond ((and (eq (first type) 'SATISFIES) (eql (length type) 2))
  8367.                           (let ((fun (second type)))
  8368.                             (unless (symbolp (second type))
  8369.                               (c-warn #+DEUTSCH "~S: Argument zu SATISFIES muß Symbol sein: ~S"
  8370.                                       #+ENGLISH "~S: argument to SATISFIES must be a symbol: ~S"
  8371.                                       #+FRANCAIS "~S : L'argument de SATISFIES doit être un symbole: ~S"
  8372.                                       'typep (second type)
  8373.                               )
  8374.                               (throw 'c-TYPEP nil)
  8375.                             )
  8376.                             (return-from c-TYPEP
  8377.                               (c-GLOBAL-FUNCTION-CALL-form `(,fun ,objform))
  8378.                         ) ) )
  8379.                         ((eq (first type) 'MEMBER)
  8380.                           (return-from c-TYPEP
  8381.                             (let ((*form* `(CASE ,objform (,(rest type) T) (t NIL))))
  8382.                               (c-CASE)
  8383.                         ) ) )
  8384.                         ((and (eq (first type) 'EQL) (eql (length type) 2))
  8385.                           (return-from c-TYPEP
  8386.                             (let ((*form* `(EQL ,objform ',(second type))))
  8387.                               (c-EQL)
  8388.                         ) ) )
  8389.                         ((and (eq (first type) 'NOT) (eql (length type) 2))
  8390.                           (return-from c-TYPEP
  8391.                             (c-GLOBAL-FUNCTION-CALL-form
  8392.                               `(NOT (TYPEP ,objform ',(second type)))
  8393.                         ) ) )
  8394.                         ((or (eq (first type) 'AND) (eq (first type) 'OR))
  8395.                           (return-from c-TYPEP
  8396.                             (c-form
  8397.                               (let ((objvar (gensym)))
  8398.                                 `(LET ((,objvar ,objform))
  8399.                                    (,(first type) ; AND oder OR
  8400.                                     ,@(mapcar #'(lambda (typei) `(TYPEP ,objvar ',typei)) (rest type))
  8401.                                  ) )
  8402.                         ) ) ) )
  8403.                         ((setq h (assoc (first type) c-typep-alist3))
  8404.                           (setq h (cdr h))
  8405.                           (let* ((objvar (gensym))
  8406.                                  (testform (apply h objvar (rest type)))
  8407.                                  (lambdabody `((,objvar) ,testform)))
  8408.                             (return-from c-TYPEP
  8409.                               (let ((*form* `((lambda ,@lambdabody) ,objform)))
  8410.                                 (c-FUNCALL-INLINE
  8411.                                   (symbol-suffix '#:TYPEP (symbol-name (first type)))
  8412.                                   (list objform)
  8413.                                   nil
  8414.                                   lambdabody
  8415.                                   nil
  8416.                         ) ) ) ) )
  8417.               ) ) )
  8418.               ((and (clos::class-p type) (eq (get (clos:class-name type) 'CLOS::CLASS) type))
  8419.                 (return-from c-TYPEP
  8420.                   (c-form `(CLOS::SUBCLASSP (CLOS:CLASS-OF ,objform)
  8421.                              (LOAD-TIME-VALUE (CLOS:FIND-CLASS ',(clos:class-name type)))
  8422.                            )
  8423.               ) ) )
  8424.     ) ) )
  8425.     (c-GLOBAL-FUNCTION-CALL 'TYPEP)
  8426. ) )
  8427.  
  8428.  
  8429.  
  8430. ;                     Z W E I T E R   P A S S
  8431.  
  8432. ; eine Tabelle von Paaren (fnode n).
  8433. ; Jedes Paar zeigt an, daß im 3. Pass in der Konstanten Nummer n des
  8434. ; funktionalen Objektes von fnode der dort stehende fnode durch das durch ihn
  8435. ; erzeugte funktionale Objekt zu ersetzen ist.
  8436. (defvar *fnode-fixup-table*)
  8437.  
  8438. ; macht aus dem ANODE-Baum zum fnode *func* ein funktionales Objekt:
  8439. (defun pass2 (*func*)
  8440.   (when (anode-p (fnode-code *func*)) ; falls 2. Pass noch nicht durchgeführt:
  8441.     ; erst den Code flachklopfen, optimieren und assemblieren:
  8442.     (let ((code-list (compile-to-LAP))) ; Code flachklopfen und in Stücke zerteilen,
  8443.                                         ; optimieren und zu einer Liste machen
  8444.       (when (fnode-gf-p *func*) (setq code-list (CONST-to-LOADV code-list))) ; evtl. CONSTs umwandeln
  8445.       (let (#+CLISP3 (SPdepth (SP-depth code-list))) ; Stackbedarf bestimmen
  8446.         (setq code-list (insert-combined-LAPs code-list)) ; kombinierte Operationen einführen
  8447.         (create-fun-obj *func* (assemble-LAP code-list) #+CLISP3 SPdepth) ; assemblieren und funkt. Objekt
  8448.     ) )
  8449.     ; dann die Sub-Funktionen durch den 2. Pass jagen
  8450.     (dolist (x (fnode-Consts *func*)) (if (fnode-p x) (pass2 x)))
  8451. ) )
  8452.  
  8453. #|
  8454.  
  8455. pass2 ruft den 1. Schritt auf.
  8456.  
  8457. Nach dem 1. Schritt ist der Code in kleine Stücke aufgeteilt, jeweils von
  8458. einem Label bis zu einem Wegsprung (JMP, JMPCASE, JMPCASE1-TRUE, JMPCASE1-FALSE,
  8459. JMPHASH, RETURN-FROM, GO, RET, THROW, ERROR). Die Teile stecken (jeweils als
  8460. Liste in umgekehrter Reihenfolge, mit dem Label als letztem CDR) im Vektor
  8461. *code-parts*.
  8462. (symbol-value label) enthält eine Liste der Referenzen von label, und zwar in
  8463. der Form:
  8464.  - Index in *code-parts*, wenn die Referenz der entsprechende Wegsprung ist;
  8465.  - opcode sonst, wobei opcode der Befehl ist, in dem label auftritt.
  8466. Nach dem 1. Schritt enthält der Code nur noch Tags (Symbole) und Listen aus
  8467. Symbolen und Zahlen. Es darf daher mit SUBST und EQUAL gearbeitet werden.
  8468.  
  8469. Der 1. Schritt ruft, sobald er mit einem Stück fertig ist, den 2. Schritt
  8470. auf.
  8471.  
  8472. Dann ruft pass2 den 3. Schritt auf. Es handelt sich hier um Optimierungen,
  8473. die, wenn sie erfolgreich waren, weitere dieser Optimierungen aufrufen.
  8474.  
  8475. |#
  8476.  
  8477. #|
  8478.                              1. Schritt:
  8479.           Expansion von Code-Teilen, Aufteilen des Codes in Stücke
  8480.  
  8481. Verändert werden:
  8482.  
  8483. vorher                           nachher
  8484.  
  8485. (CONST const)                    (CONST n)
  8486. (FCONST fnode)                   (CONST n), Fixup für 3. Pass merken
  8487. (BCONST block)                   (CONST n)
  8488. (GCONST tagbody)                 (CONST n)
  8489. (GET var venvc stackz)           (LOAD n) oder (LOADI k n) oder (LOADC n m)
  8490.                                  oder (LOADIC k n m) oder (LOADV k m)
  8491.                                  oder (GETVALUE n) oder (CONST n)
  8492. (SET var venvc stackz)           (STORE n) oder (STOREI k n) oder (STOREC n m)
  8493.                                  oder (STOREIC k n m) oder (STOREV k m)
  8494.                                  oder (SETVALUE n)
  8495. (SETVALUE symbol)                (SETVALUE n)
  8496. (GETVALUE symbol)                (GETVALUE n)
  8497. (BIND const)                     (BIND n)
  8498. (UNWIND stackz1 stackz2 for-value) eine Folge von
  8499.                                  (SKIP n), (SKIPI k n), (SKIPSP k), (VALUES0),
  8500.                                  (UNWIND-PROTECT-CLEANUP), (UNBIND1),
  8501.                                  (BLOCK-CLOSE), (TAGBODY-CLOSE)
  8502. (JMPIF label)                    (JMPCASE label new-label) new-label
  8503. (JMPIFNOT label)                 (JMPCASE new-label label) new-label
  8504. (JMPIF1 label)                   (JMPCASE1-TRUE label new-label) new-label
  8505. (JMPIFNOT1 label)                (JMPCASE1-FALSE new-label label) new-label
  8506. (JMPHASH test ((obj1 . label1) ... (objm . labelm)) label . labels)
  8507.                                  (JMPHASH n ht label . labels)
  8508.                                  wobei ht = Hash-Tabelle (obji -> labeli) ist
  8509. (VENV venvc stackz)              (VENV) oder (NIL)
  8510.                                  oder (LOAD n) oder (LOADI k n)
  8511. (COPY-CLOSURE fnode n)           (COPY-CLOSURE m n), Fixup für 3. Pass merken
  8512. (CALLP)                          gestrichen
  8513. (CALL k fun)                     (CALL k n)
  8514. (CALL0 fun)                      (CALL0 n)
  8515. (CALL1 fun)                      (CALL1 n)
  8516. (CALL2 fun)                      (CALL2 n)
  8517. (FUNCALLP)                       (PUSH)
  8518. (APPLYP)                         (PUSH)
  8519. (JMPIFBOUNDP var venvc stackz label)
  8520.                                  (JMPIFBOUNDP n label)
  8521. (BOUNDP var venvc stackz)        (BOUNDP n)
  8522. (BLOCK-OPEN const label)         (BLOCK-OPEN n label)
  8523. (RETURN-FROM const)              (RETURN-FROM n)
  8524. (RETURN-FROM block)              (RETURN-FROM n)
  8525. (TAGBODY-OPEN m label1 ... labelm)
  8526.                                  (TAGBODY-OPEN m label1 ... labelm)
  8527. (GO const k)                     (GO n k)
  8528. (GO tagbody k)                   (GO n k)
  8529.  
  8530.  
  8531. unverändert bleiben:
  8532. (NIL)
  8533. (PUSH-NIL n)
  8534. (T)
  8535. (STORE n)
  8536. (UNBIND1)
  8537. (PROGV)
  8538. (PUSH)
  8539. (POP)
  8540. (RET)
  8541. (JMP label)
  8542. (JSR m label)
  8543. (MAKE-VECTOR1&PUSH n)
  8544. (CALLS1 n)
  8545. (CALLS2 n)
  8546. (CALLSR m n)
  8547. (CALLC)
  8548. (CALLCKEY)
  8549. (FUNCALL n)
  8550. (APPLY n)
  8551. (PUSH-UNBOUND n)
  8552. (UNLIST n m)
  8553. (UNLIST* n m)
  8554. (VALUES0)
  8555. (VALUES1)
  8556. (STACK-TO-MV n)
  8557. (MV-TO-STACK)
  8558. (NV-TO-STACK n)
  8559. (MV-TO-LIST)
  8560. (LIST-TO-MV)
  8561. (MVCALLP)
  8562. (MVCALL)
  8563. (BLOCK-CLOSE)
  8564. (TAGBODY-CLOSE-NIL)
  8565. (TAGBODY-CLOSE)
  8566. (CATCH-OPEN label)
  8567. (CATCH-CLOSE)
  8568. (THROW)
  8569. (UNWIND-PROTECT-OPEN label)
  8570. (UNWIND-PROTECT-NORMAL-EXIT)
  8571. (UNWIND-PROTECT-CLOSE label)
  8572. (UNWIND-PROTECT-CLEANUP)
  8573. (NOT)
  8574. (EQ)
  8575. (CAR)
  8576. (CDR)
  8577. (CONS)
  8578. (ATOM)
  8579. (CONSP)
  8580. (SYMBOL-FUNCTION)
  8581. (SVREF)
  8582. (SVSET)
  8583. (LIST n)
  8584. (LIST* n)
  8585. (ERROR n)
  8586.  
  8587. Neue Operationen:
  8588.  
  8589. (JMP label boolvalue)            Sprung zu label, boolvalue beschreibt den 1.
  8590.                                  Wert: FALSE falls =NIL, TRUE falls /=NIL,
  8591.                                  NIL falls unbekannt.
  8592.  
  8593. (JMPCASE label1 label2)          Sprung zu label1, falls A0 /= NIL,
  8594.                                  bzw. zu label2, falls A0 = NIL.
  8595.  
  8596. (JMPCASE1-TRUE label1 label2)    Falls A0 /= NIL: Sprung nach label1, 1 Wert.
  8597.                                  Falls A0 = NIL: Sprung nach label2.
  8598.  
  8599. (JMPCASE1-FALSE label1 label2)   Falls A0 /= NIL: Sprung nach label1.
  8600.                                  Falls A0 = NIL: Sprung nach label2, 1 Wert.
  8601.  
  8602. (JMPTAIL m n label)              Verkleinerung des Stack-Frames von n auf m,
  8603.                                  dann Sprung zu label mit undefinierten Werten.
  8604.  
  8605. |#
  8606.  
  8607. ; Ein Vektor mit Fill-Pointer, der die Codestücke enthält:
  8608. (defvar *code-parts*)
  8609.  
  8610. ; Ein gleichlanger Vektor mit Fill-Pointer, der zu jedem Codestück eine
  8611. ; "Position" enthält, wo das Stück am Ende landen soll (0 = ganz am Anfang,
  8612. ; je höher, desto weiter hinten).
  8613. (defvar *code-positions*)
  8614.  
  8615. ; trägt eine Konstante in (fnode-consts *func*) ein und liefert deren Index n.
  8616. ; value ist der Wert der Konstanten, form eine Form mit diesem Wert oder NIL.
  8617. (defun const-index (value form &optional (func *func*))
  8618.   (let ((const-list (fnode-consts func))
  8619.         (forms-list (fnode-consts-forms func))
  8620.         (n (fnode-Consts-Offset func)))
  8621.     (if (null const-list)
  8622.       (progn
  8623.         (setf (fnode-consts func) (list value))
  8624.         (setf (fnode-consts-forms func) (list form))
  8625.         n
  8626.       )
  8627.       (loop
  8628.         (when (eql (car const-list) value)
  8629.           (when (and (null (car forms-list)) form) (setf (car forms-list) form))
  8630.           (return n)
  8631.         )
  8632.         (incf n)
  8633.         (when (null (cdr const-list))
  8634.           (setf (cdr const-list) (list value))
  8635.           (setf (cdr forms-list) (list form))
  8636.           (return n)
  8637.         )
  8638.         (setq const-list (cdr const-list))
  8639.         (setq forms-list (cdr forms-list))
  8640. ) ) ) )
  8641.  
  8642. ; sucht eine Konstante in (fnode-Keywords *func*) und in (fnode-Consts *func*),
  8643. ; trägt sie eventuell in (fnode-Consts *func*) ein. Liefert ihren Index n.
  8644. (defun kconst-index (value form &optional (func *func*))
  8645.   (when (keywordp value) ; nur bei Keywords lohnt sich die Suche
  8646.     (do ((n (fnode-Keyword-Offset func) (1+ n))
  8647.          (L (fnode-Keywords func) (cdr L)))
  8648.         ((null L))
  8649.       (if (eq (car L) value) (return-from kconst-index n))
  8650.   ) )
  8651.   (const-index value form func)
  8652. )
  8653. (defun kconst-index-1 (const)
  8654.   (kconst-index (const-value const) (const-form const))
  8655. )
  8656.  
  8657. ; (make-const-code value form) liefert den Code, der das Objekt value,
  8658. ; entstanden aus form, als 1 Wert nach A0 bringt.
  8659. (defun make-const-code (value form)
  8660.   (cond ((eq value 'nil) '(NIL) )
  8661.         ((eq value 't) '(T) )
  8662.         (t `(CONST ,(kconst-index value form)) )
  8663. ) )
  8664.  
  8665. ; (bconst-index block) liefert den Index in FUNC, an dem dieser Block steht.
  8666. (defun bconst-index (block &optional (func *func*))
  8667. ; (+ (fnode-Blocks-Offset func)
  8668. ;    (position block (fnode-Blocks func) :test #'eq)
  8669. ; )
  8670.   (do ((n (fnode-Blocks-Offset func) (1+ n))
  8671.        (L (fnode-Blocks func) (cdr L)))
  8672.       ((eq (car L) block) n)
  8673. ) )
  8674.  
  8675. ; (gconst-index tagbody) liefert den Index in FUNC, an dem dieser Tagbody steht.
  8676. (defun gconst-index (tagbody &optional (func *func*))
  8677. ; (+ (fnode-Tagbodys-Offset func)
  8678. ;    (position tagbody (fnode-Tagbodys func) :test #'eq)
  8679. ; )
  8680.   (do ((n (fnode-Tagbodys-Offset func) (1+ n))
  8681.        (L (fnode-Tagbodys func) (cdr L)))
  8682.       ((eq (car L) tagbody) n)
  8683. ) )
  8684.  
  8685. ; (fconst-index fnode) liefert den Index in FUNC, an dem dieser fnode in den
  8686. ; Konstanten steht. Wenn nötig, wird er eingefügt und in *fnode-fixup-table*
  8687. ; vermerkt.
  8688. (defun fconst-index (fnode &optional (func *func*))
  8689.   (if (member fnode (fnode-Consts func))
  8690.     (const-index fnode nil)
  8691.     (let ((n (const-index fnode nil)))
  8692.       (push (list func n) *fnode-fixup-table*)
  8693.       n
  8694. ) ) )
  8695.  
  8696. ; Hilfsvariablen beim rekursiven Aufruf von traverse-anode:
  8697.  
  8698. ; Das aktuelle Codestück, eine umgedrehte Liste von Instruktionen, die
  8699. ; mit dem Start-Label als letztem nthcdr endet.
  8700. (defvar *code-part*)
  8701.  
  8702. ; und seine Nummer (Index in *code-parts*)
  8703. (defvar *code-index*)
  8704.  
  8705. ; Flag, ob "toter Code" (d.h. Code, der nicht erreichbar ist) vorliegt
  8706. (defvar *dead-code*)
  8707.  
  8708. ; Für Sprungkettenverkürzung in traverse-anode: Liste aller bereits
  8709. ; durchgeführten Label-Substitutionen ((old-label . new-label) ...)
  8710. (defvar *label-subst*)
  8711.  
  8712. ; Der aktuelle Wert, interpretiert als boolescher Wert:
  8713. ; FALSE falls =NIL, TRUE falls /=NIL, NIL falls unbekannt.
  8714. ; (Keine Einschränkung an die Anzahl der Werte!)
  8715. (defvar *current-value*)
  8716.  
  8717. ; Liste der Variablen/Konstanten, deren Wert mit dem aktuellen übereinstimmt
  8718. ; (lexikalische Variablen als VARIABLE-Structures, dynamische Variablen als
  8719. ; Symbole, Konstanten als CONST-Structures).
  8720. ; Ist diese Liste nichtleer, so liegt auch genau 1 Wert vor.
  8721. (defvar *current-vars*)
  8722.  
  8723. ; Jedes Label (ein Gensym-Symbol) hat als Wert eine Liste aller Referenzen
  8724. ; auf label, und zwar jeweils entweder als Index i in *code-parts*, wenn es
  8725. ; sich um den Wegsprung (das Ende) von (aref *code-parts* i) handelt, oder
  8726. ; als Instruktion (einer Liste) in allen anderen Fällen. Falls das Label
  8727. ; ein Codestück beginnt, steht unter (get label 'code-part) der Index in
  8728. ; *code-part* des Codestücks, das mit diesem Label anfängt. Unter
  8729. ; (get label 'for-value) steht, wieviele Werte bei einem möglichen Sprung
  8730. ; auf das Label von Bedeutung sind (NIL/ONE/ALL).
  8731. ; Eine Ausnahme stellt das "Label" NIL dar, das den Einsprungpunkt darstellt.
  8732.  
  8733. ; Ersetzt alle Referenzen auf old-label durch Referenzen auf new-label.
  8734. (defun label-subst (old-label new-label)
  8735.   ; alle Referenzen auf old-label verändern:
  8736.   (dolist (ref (symbol-value old-label))
  8737.     (nsubst new-label old-label
  8738.             (rest (if (integerp ref) (first (aref *code-parts* ref)) ref))
  8739.   ) )
  8740.   ; und als Referenzen auf new-label eintragen:
  8741.   (setf (symbol-value new-label)
  8742.     (nconc (symbol-value old-label) (symbol-value new-label))
  8743.   )
  8744.   (setf (symbol-value old-label) '())
  8745.   ; Mit old-label fängt kein Codestück mehr an:
  8746.   (remprop old-label 'code-part)
  8747. )
  8748.  
  8749. ; Aktuelles Codestück beenden und ein neues Codestück anfangen:
  8750. (defun finish-code-part ()
  8751.   ; das aktuelle Codestück vereinfachen:
  8752.   (simplify *code-part*)
  8753.   ; *code-part* in *code-parts* unterbringen:
  8754.   (vector-push-extend *code-part* *code-parts*)
  8755.   (vector-push-extend (incf *code-index*) *code-positions*)
  8756. )
  8757.  
  8758. ; Einen Wegsprung auf Label label emittieren.
  8759. ; Dadurch wird ein neues Codestück angefangen.
  8760. (defun emit-jmp (label)
  8761.   ; mit einem Wegsprung:
  8762.   (push `(JMP ,label ,*current-value*) *code-part*)
  8763.   (push *code-index* (symbol-value label))
  8764.   (finish-code-part)
  8765. )
  8766.  
  8767. ; Läuft durch den Code eines Anode durch, expandiert den Code und baut dabei
  8768. ; *code-part* weiter. Adjustiert die Variablen *current-value* usw. passend.
  8769. (defun traverse-anode (code)
  8770.   (dolist (item code)
  8771.     (if (atom item)
  8772.       (cond ((symbolp item) ; Label
  8773.              (if *dead-code*
  8774.                ; Code kann angesprungen werden, ist ab jetzt nicht mehr tot
  8775.                (setq *dead-code* nil)
  8776.                (if (symbolp *code-part*)
  8777.                  ; Label item sofort nach Label *code-part*
  8778.                  ; -> können identifiziert werden
  8779.                  (let ((old-label *code-part*) (new-label item))
  8780.                    ; substituiere *code-parts* -> item
  8781.                    (label-subst old-label new-label)
  8782.                    (setq *label-subst*
  8783.                      (acons old-label new-label
  8784.                        (nsubst new-label old-label *label-subst*)
  8785.                  ) ) )
  8786.                  ; Label mitten im Codestück -> aktuelles Codestück beenden
  8787.                  (emit-jmp item)
  8788.              ) )
  8789.              ; jetzt geht das aktuelle Codestück erst richtig los,
  8790.              ; mit dem Label item:
  8791.              (setq *code-part* item)
  8792.              (setf (get item 'code-part) (fill-pointer *code-parts*))
  8793.              ; Da noch Sprünge auf dieses Label kommen können, wissen wir
  8794.              ; nicht, was A0 enthält:
  8795.              (setq *current-value* nil *current-vars* '())
  8796.             )
  8797.             ((anode-p item) (traverse-anode (anode-code item))) ; Anode -> rekursiv
  8798.             (t (compiler-error 'traverse-anode "ITEM"))
  8799.       )
  8800.       ; item ist eine normale Instruktion
  8801.       (unless *dead-code* ; nur erreichbarer Code braucht verarbeitet zu werden
  8802.         (nsublis *label-subst* (rest item)) ; bisherige Substitutionen durchführen
  8803.         (case (first item)
  8804.           (CONST
  8805.             (let* ((c (second item))
  8806.                    (cv (const-value c)))
  8807.               (unless ; ein (CONST cv) schon in *current-vars* enthalten?
  8808.                   (dolist (v *current-vars* nil)
  8809.                     (when (and (const-p v) (eq (const-value v) cv)) (return t))
  8810.                   )
  8811.                 (push (make-const-code cv (const-form c)) *code-part*)
  8812.                 (setq *current-value* (if (null cv) 'FALSE 'TRUE)
  8813.                       *current-vars* (list c)
  8814.           ) ) ) )
  8815.           (FCONST
  8816.             (push `(CONST ,(fconst-index (second item))) *code-part*)
  8817.             (setq *current-value* 'TRUE *current-vars* '())
  8818.           )
  8819.           (BCONST
  8820.             (push `(CONST ,(bconst-index (second item))) *code-part*)
  8821.             (setq *current-value* 'TRUE *current-vars* '())
  8822.           )
  8823.           (GCONST
  8824.             (push `(CONST ,(gconst-index (second item))) *code-part*)
  8825.             (setq *current-value* 'TRUE *current-vars* '())
  8826.           )
  8827.           (GET
  8828.             (let ((var (second item))
  8829.                   (venvc (third item))
  8830.                   (stackz (fourth item)))
  8831.               (unless (member var *current-vars* :test #'eq) ; Ist bereits der aktuelle Wert = var ?
  8832.                 (push
  8833.                   (if (var-constantp var)
  8834.                     (let* ((const (var-constant var))
  8835.                            (val (const-value const)))
  8836.                       (setq *current-value* (if (null val) 'FALSE 'TRUE))
  8837.                       (if (fnode-p val)
  8838.                         ; FNODEs als Werte können (fast) nur von LABELS stammen
  8839.                         `(CONST ,(fconst-index val))
  8840.                         (make-const-code val (const-form const))
  8841.                     ) )
  8842.                     (progn
  8843.                       (setq *current-value* nil)
  8844.                       (if (var-specialp var)
  8845.                         `(GETVALUE ,(kconst-index (setq var (var-name var)) nil))
  8846.                         (if (var-closurep var)
  8847.                           (multiple-value-bind (k n m)
  8848.                               (zugriff-in-closure var venvc stackz)
  8849.                             (if n
  8850.                               (if k `(LOADIC ,k ,n ,m) `(LOADC ,n ,m))
  8851.                               `(LOADV ,k ,(1+ m))
  8852.                           ) )
  8853.                           ; lexikalisch und im Stack, also in derselben Funktion
  8854.                           (multiple-value-bind (k n)
  8855.                               (zugriff-in-stack stackz (var-stackz var))
  8856.                             (if k `(LOADI ,k ,n) `(LOAD ,n) )
  8857.                   ) ) ) ) )
  8858.                   *code-part*
  8859.                 )
  8860.                 (setq *current-vars* (list var))
  8861.           ) ) )
  8862.           (SET
  8863.             (let ((var (second item))
  8864.                   (venvc (third item))
  8865.                   (stackz (fourth item)))
  8866.               (unless (member var *current-vars* :test #'eq) ; Ist bereits der aktuelle Wert = var ?
  8867.                 (push
  8868.                   (if (var-specialp var)
  8869.                     `(SETVALUE ,(kconst-index (setq var (var-name var)) nil))
  8870.                     (if (var-closurep var)
  8871.                       (multiple-value-bind (k n m)
  8872.                           (zugriff-in-closure var venvc stackz)
  8873.                         (if n
  8874.                           (if k `(STOREIC ,k ,n ,m) `(STOREC ,n ,m))
  8875.                           `(STOREV ,k ,(1+ m))
  8876.                       ) )
  8877.                       ; lexikalisch und im Stack, also in derselben Funktion
  8878.                       (multiple-value-bind (k n)
  8879.                           (zugriff-in-stack stackz (var-stackz var))
  8880.                         (if k `(STOREI ,k ,n) `(STORE ,n) )
  8881.                   ) ) )
  8882.                   *code-part*
  8883.                 )
  8884.                 (push var *current-vars*) ; *current-value* bleibt unverändert
  8885.           ) ) )
  8886.           (GETVALUE
  8887.             (let ((symbol (second item)))
  8888.               (unless (member symbol *current-vars* :test #'eq)
  8889.                 (push `(GETVALUE ,(kconst-index symbol nil)) *code-part*)
  8890.                 (setq *current-value* nil *current-vars* (list symbol))
  8891.           ) ) )
  8892.           (SETVALUE
  8893.             (let ((symbol (second item)))
  8894.               (unless (member symbol *current-vars* :test #'eq)
  8895.                 (push `(SETVALUE ,(kconst-index symbol nil)) *code-part*)
  8896.                 (push symbol *current-vars*) ; *current-value* bleibt unverändert
  8897.           ) ) )
  8898.           (BIND
  8899.             (push `(BIND ,(kconst-index-1 (second item))) *code-part*)
  8900.             (setq *current-value* nil *current-vars* '()) ; undefinierte Werte
  8901.           )
  8902.           (UNWIND ; mehrzeilige Umwandlung
  8903.             (traverse-anode
  8904.               (expand-UNWIND (second item) (third item) (fourth item))
  8905.           ) )
  8906.           ((JMPIF JMPIFNOT JMPIF1 JMPIFNOT1)
  8907.             (if (null *current-value*)
  8908.               (let ((label (second item))
  8909.                     (new-label (make-label 'NIL)))
  8910.                 (push
  8911.                   (case (first item)
  8912.                     (JMPIF `(JMPCASE ,label ,new-label))
  8913.                     (JMPIFNOT `(JMPCASE ,new-label ,label))
  8914.                     (JMPIF1 `(JMPCASE1-TRUE ,label ,new-label))
  8915.                     (JMPIFNOT1 `(JMPCASE1-FALSE ,new-label ,label))
  8916.                   )
  8917.                   *code-part*
  8918.                 )
  8919.                 (push *code-index* (symbol-value (second item)))
  8920.                 (push *code-index* (symbol-value new-label))
  8921.                 (finish-code-part)
  8922.                 (setf (get new-label 'code-part) (fill-pointer *code-parts*))
  8923.                 (setq *code-part* new-label)
  8924.                 ; *current-value* und *current-vars* bleiben unverändert.
  8925.               )
  8926.               ; boolescher Wert beim Wegsprung bekannt
  8927.               (if (if (eq *current-value* 'FALSE)
  8928.                     (memq (first item) '(JMPIF JMPIF1)) ; Wert=NIL -> JMPIF weglassen
  8929.                     (memq (first item) '(JMPIFNOT JMPIFNOT1)) ; Wert/=NIL -> JMPIFNOT weglassen
  8930.                   )
  8931.                 ; Sprung weglassen
  8932.                 nil
  8933.                 ; in JMP umwandeln:
  8934.                 (progn
  8935.                   (when (memq (first item) '(JMPIF1 JMPIFNOT1))
  8936.                     (push '(VALUES1) *code-part*) ; genau 1 Wert erzwingen
  8937.                   )
  8938.                   (emit-jmp (second item))
  8939.                   (setq *dead-code* t)
  8940.           ) ) ) )
  8941.           (JMPHASH
  8942.             (let ((hashtable (make-hash-table :test (second item)))
  8943.                   (labels (cddddr item)))
  8944.               (dolist (acons (third item))
  8945.                 (setf (gethash (car acons) hashtable)
  8946.                       (position (cdr acons) labels)
  8947.               ) )
  8948.               (push `(JMPHASH ,(const-index hashtable nil) ,hashtable
  8949.                               ,@(cdddr item)
  8950.                      )
  8951.                     *code-part*
  8952.             ) )
  8953.             ; Referenzen vermerken:
  8954.             (dolist (label (cdddr item))
  8955.               (push *code-index* (symbol-value label))
  8956.             )
  8957.             (finish-code-part)
  8958.             (setq *dead-code* t)
  8959.           )
  8960.           (VENV
  8961.             (let ((venvc (second item))
  8962.                   (stackz (third item)))
  8963.               (loop ; in venvc die NILs übergehen
  8964.                 (when (car venvc) (return))
  8965.                 (setq venvc (cdr venvc))
  8966.               )
  8967.               (push
  8968.                 (if (consp (car venvc)) ; aus dem Stack holen
  8969.                   (multiple-value-bind (k n)
  8970.                       (zugriff-in-stack stackz (cdr (car venvc)))
  8971.                     (if k `(LOADI ,k ,n) `(LOAD ,n) )
  8972.                   )
  8973.                   (if (eq (car venvc) *func*)
  8974.                     (if (fnode-Venvconst *func*) '(VENV) '(NIL))
  8975.                     (compiler-error 'traverse-anode 'VENV)
  8976.                 ) )
  8977.                 *code-part*
  8978.               )
  8979.               (if (equal (car *code-part*) '(NIL))
  8980.                 (setq *current-value* 'FALSE *current-vars* (list (make-const :value 'NIL)))
  8981.                 (setq *current-value* nil *current-vars* '())
  8982.               )
  8983.           ) )
  8984.           (COPY-CLOSURE
  8985.             (push `(COPY-CLOSURE ,(fconst-index (second item)) ,(third item))
  8986.                    *code-part*
  8987.             )
  8988.             (setq *current-value* 'TRUE *current-vars* '())
  8989.           )
  8990.           (CALLP) ; wird gestrichen
  8991.           (CALL
  8992.             (push `(CALL ,(second item) ,(kconst-index-1 (third item)))
  8993.                    *code-part*
  8994.             )
  8995.             (setq *current-value* nil *current-vars* '())
  8996.           )
  8997.           ((CALL0 CALL1 CALL2)
  8998.             (push `(,(first item) ,(kconst-index-1 (second item)))
  8999.                   *code-part*
  9000.             )
  9001.             (setq *current-value* nil *current-vars* '())
  9002.           )
  9003.           ((FUNCALLP APPLYP)
  9004.             (push '(PUSH) *code-part*)
  9005.             (setq *current-value* nil *current-vars* '())
  9006.           )
  9007.           ((JMPIFBOUNDP BOUNDP)
  9008.             (let ((var (second item))
  9009.                   (stackz (fourth item))
  9010.                  )
  9011.               (when (var-closurep var)
  9012.                 (compiler-error 'traverse-anode 'var-closurep)
  9013.               )
  9014.               (multiple-value-bind (k n)
  9015.                   (zugriff-in-stack stackz (var-stackz var))
  9016.                 (when k (compiler-error 'traverse-anode 'var-stackz))
  9017.                 (push `(,(first item) ,n ,@(cddddr item)) *code-part*)
  9018.                 (when (eq (first item) 'JMPIFBOUNDP)
  9019.                   (push (first *code-part*) (symbol-value (fifth item)))
  9020.                 )
  9021.                 (setq *current-value* nil *current-vars* '()) ; undefinierte Werte
  9022.           ) ) )
  9023.           (BLOCK-OPEN
  9024.             (let ((label (third item)))
  9025.               (push `(BLOCK-OPEN ,(kconst-index-1 (second item)) ,label)
  9026.                      *code-part*
  9027.               )
  9028.               (push (first *code-part*) (symbol-value label))
  9029.           ) )
  9030.           (RETURN-FROM
  9031.             (push
  9032.               (if (block-p (second item))
  9033.                 `(RETURN-FROM ,(bconst-index (second item)))
  9034.                 `(RETURN-FROM ,(kconst-index-1 (second item)))
  9035.               )
  9036.               *code-part*
  9037.             )
  9038.             (finish-code-part)
  9039.             (setq *dead-code* t)
  9040.           )
  9041.           (TAGBODY-OPEN
  9042.             (push item *code-part*)
  9043.             (dolist (label (cddr item)) (push item (symbol-value label)))
  9044.           )
  9045.           (GO
  9046.             (push
  9047.               (if (tagbody-p (second item))
  9048.                 `(GO ,(gconst-index (second item)) ,(third item))
  9049.                 `(GO ,(kconst-index-1 (second item)) ,(third item))
  9050.               )
  9051.               *code-part*
  9052.             )
  9053.             (finish-code-part)
  9054.             (setq *dead-code* t)
  9055.           )
  9056.           ((NIL TAGBODY-CLOSE-NIL)
  9057.             (push item *code-part*)
  9058.             (setq *current-value* 'FALSE *current-vars* (list (make-const :value 'NIL)))
  9059.           )
  9060.           (VALUES0
  9061.             (push item *code-part*)
  9062.             (setq *current-value* 'FALSE *current-vars* '())
  9063.           )
  9064.           ((SKIP SKIPI SKIPSP VALUES1 MVCALLP BLOCK-CLOSE TAGBODY-CLOSE
  9065.             CATCH-CLOSE UNWIND-PROTECT-NORMAL-EXIT
  9066.             STORE ; STORE nur auf Funktionsargumente innerhalb eines
  9067.                   ; Funktionsaufrufs, vgl. c-DIRECT-FUNCTION-CALL
  9068.            )
  9069.             (push item *code-part*)
  9070.           )
  9071.           ((T)
  9072.             (push item *code-part*)
  9073.             (setq *current-value* 'TRUE *current-vars* (list (make-const :value 'T)))
  9074.           )
  9075.           ((RET THROW ERROR)
  9076.             (push item *code-part*)
  9077.             (finish-code-part)
  9078.             (setq *dead-code* t)
  9079.           )
  9080.           (JMP
  9081.             (emit-jmp (second item))
  9082.             (setq *dead-code* t)
  9083.           )
  9084.           (JSR
  9085.             (push item *code-part*)
  9086.             (push item (symbol-value (third item)))
  9087.             (setq *current-value* nil *current-vars* '())
  9088.           )
  9089.           ((CATCH-OPEN UNWIND-PROTECT-OPEN)
  9090.             (push item *code-part*)
  9091.             (push item (symbol-value (second item)))
  9092.           )
  9093.           (UNWIND-PROTECT-CLOSE
  9094.             (push item *code-part*)
  9095.             (push item (symbol-value (second item)))
  9096.             (setq *current-value* nil *current-vars* '()) ; Werte werden weggeworfen
  9097.           )
  9098.           ((PUSH-NIL PROGV PUSH POP MAKE-VECTOR1&PUSH CALLS1 CALLS2 CALLSR
  9099.             CALLC CALLCKEY FUNCALL APPLY PUSH-UNBOUND UNLIST UNLIST*
  9100.             STACK-TO-MV MV-TO-STACK NV-TO-STACK MV-TO-LIST LIST-TO-MV MVCALL
  9101.             NOT EQ CAR CDR ATOM CONSP SYMBOL-FUNCTION SVREF SVSET
  9102.            )
  9103.             (push item *code-part*)
  9104.             (setq *current-value* nil *current-vars* '())
  9105.           )
  9106.           ((CONS LIST LIST*)
  9107.             (push item *code-part*)
  9108.             (setq *current-value* 'TRUE *current-vars* '())
  9109.           )
  9110.           ((UNWIND-PROTECT-CLEANUP)
  9111.             (push item *code-part*)
  9112.             (setq *current-vars* '()) ; Kann Variablenwerte zerstören
  9113.           )
  9114.           ((UNBIND1)
  9115.             (push item *code-part*)
  9116.             (setq *current-vars* (delete-if #'symbolp *current-vars*)) ; Kann Werte dynamischer Variablen zerstören
  9117.           )
  9118.           (t (compiler-error 'traverse-anode "LISTITEM"))
  9119. ) ) ) ) )
  9120.  
  9121. ; Hilfsfunktionen nach dem 1. Schritt:
  9122.  
  9123. ; Kommt eine Instruktion item dazu, die vielleicht Label-Referenzen enthält,
  9124. ; so ist note-references aufzurufen. Dieses notiert die Label-Referenzen in
  9125. ; item. item gehöre zu (aref *code-parts* index).
  9126. ; Wird eine Instruktion item entfernt, die vielleicht Label-Referenzen enthält,
  9127. ; so ist remove-references aufzurufen. Dieses notiert das Wegfallen der
  9128. ; Label-Referenzen in item. item gehöre zu (aref *code-parts* index).
  9129. ; Liefert auch die Liste der in item enthaltenen Labels.
  9130. (macrolet ((references ()
  9131.              `(case (first item)
  9132.                 (JMP (end-ref (second item)))
  9133.                 ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9134.                  (end-ref (second item)) (end-ref (third item))
  9135.                 )
  9136.                 (JMPHASH (dolist (label (cdddr item)) (end-ref label)))
  9137.                 ((JMPIFBOUNDP CATCH-OPEN UNWIND-PROTECT-OPEN UNWIND-PROTECT-CLOSE)
  9138.                  (mid-ref (second item))
  9139.                 )
  9140.                 ((BLOCK-OPEN JSR) (mid-ref (third item)))
  9141.                 (JMPTAIL (mid-ref (fourth item)))
  9142.                 (TAGBODY-OPEN (dolist (label (cddr item)) (mid-ref label)))
  9143.               )
  9144.           ))
  9145.   (defun note-references (item &optional index)
  9146.     (macrolet ((end-ref (label) `(push index (symbol-value ,label)))
  9147.                (mid-ref (label) `(push item (symbol-value ,label))))
  9148.       (references)
  9149.   ) )
  9150.   (defun remove-references (item &optional index &aux (labellist '()))
  9151.     (macrolet ((end-ref (label)
  9152.                  (let ((labelvar (gensym)))
  9153.                    `(let ((,labelvar ,label))
  9154.                       (setf (symbol-value ,labelvar) (delete index (symbol-value ,labelvar)))
  9155.                       (pushnew ,labelvar labellist)
  9156.                     )
  9157.                ) )
  9158.                (mid-ref (label)
  9159.                  (let ((labelvar (gensym)))
  9160.                    `(let ((,labelvar ,label))
  9161.                       (setf (symbol-value ,labelvar) (delete item (symbol-value ,labelvar)))
  9162.                       (pushnew ,labelvar labellist)
  9163.                     )
  9164.               )) )
  9165.       (references)
  9166.       labellist
  9167.   ) )
  9168. )
  9169.  
  9170. #|
  9171.                               2. Schritt
  9172.                 Vereinfachung von Folgen von Operationen
  9173.  
  9174. Dieses spielt sich auf umgedrehten Codestücken ab; sie werden dabei destruktiv
  9175. verändert.
  9176.  
  9177. Vereinfachungsregeln für Operationen:
  9178.  
  9179. 1. (VALUES1) darf nach allen Instruktionen gestrichen werden, die sowieso nur
  9180.    einen Wert produzieren, und vor allen, die sowieso nur einen verwenden.
  9181.  
  9182. 2. (SKIP n1) (SKIP n2)               --> (SKIP n1+n2)
  9183.    (SKIPI k n1) (SKIP n2)            --> (SKIPI k n1+n2)
  9184.    (SKIP n1) (SKIPI k n2)            --> (SKIPI k n2)
  9185.    (SKIPI k1 n1) (SKIPI k2 n2)       --> (SKIPI k1+k2+1 n2)
  9186.    (SKIPSP k1) (SKIPI k2 n)          --> (SKIPI k1+k2 n)
  9187.    (SKIPSP k1) (SKIPSP k2)           --> (SKIPSP k1+k2)
  9188.  
  9189. 3. (NOT) (NOT) (NOT)                 --> (NOT)
  9190.    (ATOM) (NOT)                      --> (CONSP)
  9191.    (CONSP) (NOT)                     --> (ATOM)
  9192.  
  9193. 4. (LOAD 0) (SKIP n)                 --> (POP) (SKIP n-1)  für n>1
  9194.    (LOAD 0) (SKIP 1)                 --> (POP)             für n=1
  9195.    (PUSH) (SKIP n)                   --> (SKIP n-1)  für n>1
  9196.    (PUSH) (SKIP 1)                   -->             für n=1
  9197.    (NV-TO-STACK n) (SKIP n)          -->
  9198.    (NV-TO-STACK n+m) (SKIP n)        --> (NV-TO-STACK m)
  9199.    (NV-TO-STACK n) (SKIP n+m)        --> (SKIP m)
  9200.    (STORE m) (SKIP n)                --> (VALUES1) (SKIP n) für n>m
  9201.    (STORE 0) (POP)                   --> (VALUES1) (SKIP 1)
  9202.    (PUSH) (POP)                      --> (VALUES1)
  9203.    (POP) (PUSH)                      -->
  9204.    (SKIP n) (PUSH)                   --> (SKIP n-1) (STORE 0) für n>1
  9205.    (SKIP 1) (PUSH)                   --> (STORE 0)            für n=1
  9206.  
  9207. 5. (VALUES1)/... (MV-TO-STACK)       --> (VALUES1)/... (PUSH)
  9208.    (VALUES0) (MV-TO-STACK)           -->
  9209.    (STACK-TO-MV n) (MV-TO-STACK)     -->
  9210.    (STACK-TO-MV m) (NV-TO-STACK n)   --> (PUSH-NIL n-m)  für m<n
  9211.                                      -->                 für m=n
  9212.                                      --> (SKIP m-n)      für m>n
  9213.    (NIL)/(VALUES0) (NV-TO-STACK n)   --> (PUSH-NIL n)
  9214.    (VALUES1)/... (NV-TO-STACK n)     --> (VALUES1)/... (PUSH) (PUSH-NIL n-1)
  9215.  
  9216. 6. (PUSH-UNBOUND n) (PUSH-UNBOUND m) --> (PUSH-UNBOUND n+m)
  9217.  
  9218. 7. (LIST* 1)                         --> (CONS)
  9219.  
  9220. |#
  9221.  
  9222. ; Die Hash-Tabelle one-value-ops enthält diejenigen Befehle,
  9223. ; die genau einen Wert erzeugen.
  9224. (defconstant one-value-ops
  9225.   (let ((ht (make-hash-table :test #'eq)))
  9226.     (dolist (op '(NIL T CONST LOAD LOADI LOADC LOADV LOADIC STORE STOREI
  9227.                   STOREC STOREV STOREIC GETVALUE SETVALUE POP VENV
  9228.                   COPY-CLOSURE BOUNDP VALUES1 MV-TO-LIST TAGBODY-CLOSE-NIL
  9229.                   NOT EQ CAR CDR CONS ATOM CONSP SYMBOL-FUNCTION SVREF SVSET
  9230.                   LIST LIST*
  9231.             )    )
  9232.       (setf (gethash op ht) t)
  9233.     )
  9234.     ht
  9235. ) )
  9236.  
  9237. ; Der Wert zu einem Key in dieser Hash-Tabelle gibt an, wieviele Werte bei
  9238. ; der Ausführung der entsprechenden Operation benötigt werden
  9239. ; (vgl. *for-value*):
  9240. ; NIL : Werte werden weggeworfen.
  9241. ; ONE : Ein Wert wird verwendet, die übrigen weggeworfen.
  9242. ; ALL : Alle Werte werden verwendet.
  9243. ; Operationen, die ihre Werte nicht verändern, werden hierin nicht
  9244. ; aufgeführt.
  9245. (defconstant for-value-table
  9246.   (let ((ht (make-hash-table :test #'eq)))
  9247.     (dolist (op '(NIL PUSH-NIL T CONST LOAD LOADI LOADC LOADV LOADIC
  9248.                   GETVALUE POP JSR JMPTAIL VENV COPY-CLOSURE CALL CALL0
  9249.                   CALLS1 CALLS2 CALLSR FUNCALL PUSH-UNBOUND JMPIFBOUNDP
  9250.                   BOUNDP VALUES0 STACK-TO-MV MVCALL
  9251.                   BLOCK-OPEN TAGBODY-OPEN TAGBODY-CLOSE-NIL GO
  9252.                   UNWIND-PROTECT-OPEN UNWIND-PROTECT-CLOSE LIST ERROR
  9253.             )    )
  9254.       (setf (gethash op ht) 'NIL)
  9255.     )
  9256.     (dolist (op '(STORE STOREI STOREC STOREV STOREIC SETVALUE BIND PROGV PUSH
  9257.                   MAKE-VECTOR1&PUSH CALL1 CALL2 CALLC CALLCKEY APPLY UNLIST
  9258.                   UNLIST* VALUES1 LIST-TO-MV MVCALLP CATCH-OPEN NOT EQ CAR CDR
  9259.                   CONS ATOM CONSP SYMBOL-FUNCTION SVREF SVSET LIST*
  9260.             )    )
  9261.       (setf (gethash op ht) 'ONE)
  9262.     )
  9263.     (dolist (op '(MV-TO-STACK NV-TO-STACK MV-TO-LIST RETURN-FROM THROW
  9264.                   UNWIND-PROTECT-NORMAL-EXIT
  9265.             )    )
  9266.       (setf (gethash op ht) 'ALL)
  9267.     )
  9268.     ; Nicht in der Tabelle, weil sie die Werte unverändert lassen:
  9269.     ;           '(UNBIND1 SKIP SKIPI SKIPSP BLOCK-CLOSE TAGBODY-CLOSE
  9270.     ;             CATCH-CLOSE UNWIND-PROTECT-CLEANUP
  9271.     ;            )
  9272.     ; Nicht in der Tabelle, weil es Wegsprünge sind:
  9273.     ;   ONE:    '(JMPHASH)
  9274.     ;   ALL:    '(RET JMP JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9275.     ht
  9276. ) )
  9277.  
  9278. ; Vereinfacht ein Codestück (in umgedrehter Reihenfolge!).
  9279. ; Obige Vereinfachungsregeln werden durchgeführt, solange es geht.
  9280. ; Ergebnis ist meist NIL, oder aber (um anzuzeigen, daß weitere Optimierungen
  9281. ; möglich sind) das Anfangslabel, falls sich dessen Property for-value
  9282. ; abgeschwächt hat.
  9283. (defun simplify (codelist)
  9284.   (let ((for-value-at-end
  9285.           (let ((item (car codelist)))
  9286.             (case (first item)
  9287.               (JMP (get (second item) 'for-value))
  9288.               ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9289.                 (if (or (and (not (eq (first item) 'JMPCASE1-TRUE))
  9290.                              (eq (get (second item) 'for-value) 'ALL)
  9291.                         )
  9292.                         (and (not (eq (first item) 'JMPCASE1-FALSE))
  9293.                              (eq (get (third item) 'for-value) 'ALL)
  9294.                     )   )
  9295.                   'ALL
  9296.                   'ONE
  9297.               ) )
  9298.               (JMPHASH 'ONE)
  9299.               ((ERROR GO JMPTAIL) 'NIL)
  9300.               ((RETURN-FROM RET THROW) 'ALL)
  9301.               (t (compiler-error 'simplify "AT-END"))
  9302.         ) ) )
  9303.         (result nil)) ; evtl. das Anfangslabel
  9304.     ; for-value-at-end zeigt an, welche Werte vor dem Wegsprung benötigt werden.
  9305.     (loop
  9306.       (let ((modified nil))
  9307.         (let* ((links codelist) (mitte (cdr links)) rechts (for-value for-value-at-end))
  9308.           ; Es wandern drei Pointer durch die Codeliste: ...links.mitte.rechts...
  9309.           ; for-value zeigt an, was für Werte nach Ausführung von (car mitte),
  9310.           ; vor Ausführung von (car links), gebraucht werden.
  9311.           (loop
  9312.             nochmal
  9313.             (when (atom mitte) (return))
  9314.             (setq rechts (cdr mitte))
  9315.             (macrolet ((ersetze1 (new) ; ersetze (car mitte) durch new
  9316.                          `(progn
  9317.                             (setf (car mitte) ,new)
  9318.                             (setq modified t) (go nochmal)
  9319.                           )
  9320.                        )
  9321.                        (ersetze2 (new) ; ersetze (car mitte) und (car rechts) durch new
  9322.                          `(progn
  9323.                             ,@(unless (equal new '(car mitte))
  9324.                                 `((setf (car mitte) ,new))
  9325.                               )
  9326.                             (setf (cdr mitte) (cdr rechts))
  9327.                             (setq modified t) (go nochmal)
  9328.                           )
  9329.                        )
  9330.                        (streiche1 () ; streiche (car mitte) ersatzlos
  9331.                          `(progn
  9332.                             (setf (cdr links) (setq mitte rechts))
  9333.                             (setq modified t) (go nochmal)
  9334.                           )
  9335.                        )
  9336.                        (streiche2 () ; streiche (car mitte) und (car rechts) ersatzlos
  9337.                          `(progn
  9338.                             (setf (cdr links) (setq mitte (cdr rechts)))
  9339.                             (setq modified t) (go nochmal)
  9340.                           )
  9341.                        )
  9342.                        (erweitere2 (new1 new2) ; ersetze (car mitte) durch new1 und new2
  9343.                          `(progn
  9344.                             (setf (car mitte) ,new1)
  9345.                             (setf (cdr mitte) (cons ,new2 rechts))
  9346.                             (setq modified t) (go nochmal)
  9347.                           )
  9348.                       ))
  9349.               (when (eq for-value 'NIL)
  9350.                 ; vor einer Operation, die keine Werte braucht:
  9351.                 (case (first (car mitte))
  9352.                   ((NIL T CONST LOAD LOADI LOADC LOADV LOADIC GETVALUE VENV
  9353.                     BOUNDP VALUES0 VALUES1 MV-TO-LIST LIST-TO-MV NOT CAR CDR
  9354.                     SYMBOL-FUNCTION ATOM CONSP
  9355.                    )
  9356.                     (streiche1)
  9357.                   )
  9358.                   ((LIST LIST* STACK-TO-MV) ; (LIST n) --> (SKIP n), n>0
  9359.                                             ; (LIST* n) --> (SKIP n), n>0
  9360.                                             ; (STACK-TO-MV n) --> (SKIP n), n>0
  9361.                     (ersetze1 `(SKIP ,(second (car mitte))))
  9362.                   )
  9363.                   ((POP EQ CONS SVREF) (ersetze1 '(SKIP 1)))
  9364.               ) )
  9365.               (when (eq for-value 'ONE)
  9366.                 ; vor einer Operation, die nur einen Wert braucht:
  9367.                 (case (first (car mitte))
  9368.                   (VALUES1 (streiche1))
  9369.                   (VALUES0 (ersetze1 '(NIL)))
  9370.                   (LIST-TO-MV (ersetze1 '(CAR)))
  9371.                   (STACK-TO-MV ; (STACK-TO-MV n) --> (SKIP n-1) (POP) für n>1
  9372.                     (let ((n (second (car mitte))))
  9373.                       (erweitere2 '(POP) `(SKIP ,(- n 1)))
  9374.               ) ) ) )
  9375.               (when (consp rechts)
  9376.                 ; Gucklock umfaßt (car mitte) und (car rechts), evtl. auch mehr.
  9377.                 (case (first (car mitte))
  9378.                   (VALUES1 ; Regel 1
  9379.                     (when (gethash (first (car rechts)) one-value-ops nil)
  9380.                       ; (op ...) (VALUES1) --> (op ...)
  9381.                       (streiche1)
  9382.                   ) )
  9383.                   (NOT ; Regel 3
  9384.                     (case (first (car rechts))
  9385.                       (NOT
  9386.                         (when (and (consp (cdr rechts))
  9387.                                    (equal (cadr rechts) '(NOT))
  9388.                               )
  9389.                           ; (NOT) (NOT) (NOT) --> (NOT)
  9390.                           (streiche2)
  9391.                       ) )
  9392.                       (ATOM (ersetze2 '(CONSP))) ; (ATOM) (NOT) --> (CONSP)
  9393.                       (CONSP (ersetze2 '(ATOM))) ; (CONSP) (NOT) --> (ATOM)
  9394.                   ) )
  9395.                   (SKIP
  9396.                     (let ((n2 (second (car mitte)))) ; n2 > 0
  9397.                       (case (first (car rechts))
  9398.                         ; Regel 2
  9399.                         (SKIP ; (SKIP n1) (SKIP n2) --> (SKIP n1+n2)
  9400.                           (let ((n1 (second (car rechts))))
  9401.                             (ersetze2 `(SKIP ,(+ n1 n2)))
  9402.                         ) )
  9403.                         (SKIPI ; (SKIPI k n1) (SKIP n2) --> (SKIPI k n1+n2)
  9404.                           (let ((k (second (car rechts)))
  9405.                                 (n1 (third (car rechts))))
  9406.                             (ersetze2 `(SKIPI ,k ,(+ n1 n2)))
  9407.                         ) )
  9408.                         ; Regel 4
  9409.                         (LOAD ; (LOAD 0) (SKIP n) --> (POP) [(SKIP n-1)]
  9410.                           (when (eql (second (car rechts)) 0)
  9411.                             (if (eql n2 1)
  9412.                               (ersetze2 '(POP))
  9413.                               (progn (setf (car rechts) '(POP))
  9414.                                      (ersetze1 `(SKIP ,(- n2 1)))
  9415.                         ) ) ) )
  9416.                         (PUSH ; (PUSH) (SKIP n) --> [(SKIP n-1)]
  9417.                           (if (eql n2 1)
  9418.                             (streiche2)
  9419.                             (ersetze2 `(SKIP ,(- n2 1)))
  9420.                         ) )
  9421.                         (NV-TO-STACK
  9422.                           (let ((n1 (second (car rechts))))
  9423.                             (cond ((> n1 n2) (ersetze2 `(NV-TO-STACK ,(- n1 n2))))
  9424.                                   ((< n1 n2) (ersetze2 `(SKIP ,(- n2 n1))))
  9425.                                   (t (streiche2))
  9426.                         ) ) )
  9427.                         (STORE ; (STORE m) (SKIP n) --> (VALUES1) (SKIP n) für n>m
  9428.                           (let ((m (second (car rechts))))
  9429.                             (when (> n2 m)
  9430.                               (setf (car rechts) '(VALUES1))
  9431.                               (setq modified t) (go nochmal)
  9432.                   ) ) ) ) ) )
  9433.                   (SKIPI ; Regel 2
  9434.                     (case (first (car rechts))
  9435.                       (SKIP ; (SKIP n1) (SKIPI k n2) --> (SKIPI k n2)
  9436.                         (ersetze2 (car mitte))
  9437.                       )
  9438.                       (SKIPI ; (SKIPI k1 n1) (SKIPI k2 n2) --> (SKIPI k1+k2+1 n2)
  9439.                         (let ((k1 (second (car rechts)))
  9440.                               (k2 (second (car mitte)))
  9441.                               (n2 (third (car mitte))))
  9442.                           (ersetze2 `(SKIPI ,(+ k1 k2 1) ,n2))
  9443.                       ) )
  9444.                       (SKIPSP ; (SKIPSP k1) (SKIPI k2 n) --> (SKIPI k1+k2 n)
  9445.                         (let ((k1 (second (car rechts)))
  9446.                               (k2 (second (car mitte)))
  9447.                               (n2 (third (car mitte))))
  9448.                           (ersetze2 `(SKIPI ,(+ k1 k2) ,n2))
  9449.                   ) ) ) )
  9450.                   (SKIPSP ; Regel 2
  9451.                     (case (first (car rechts))
  9452.                       (SKIPSP ; (SKIPSP k1) (SKIPSP k2) --> (SKIPSP k1+k2)
  9453.                         (let ((k1 (second (car rechts)))
  9454.                               (k2 (second (car mitte))))
  9455.                           (ersetze2 `(SKIPSP ,(+ k1 k2)))
  9456.                   ) ) ) )
  9457.                   (POP ; Regel 4
  9458.                     (cond ((equal (car rechts) '(STORE 0))
  9459.                             ; (STORE 0) (POP) --> (VALUES1) (SKIP 1)
  9460.                             (setf (car rechts) '(VALUES1))
  9461.                             (ersetze1 '(SKIP 1))
  9462.                           )
  9463.                           ((equal (car rechts) '(PUSH))
  9464.                             ; (PUSH) (POP) --> (VALUES1)
  9465.                             (ersetze2 '(VALUES1))
  9466.                   ) )     )
  9467.                   (PUSH ; Regel 4
  9468.                     (case (first (car rechts))
  9469.                       (POP (streiche2)) ; (POP) (PUSH) streichen
  9470.                       (SKIP ; (SKIP n) (PUSH) --> [(SKIP n-1)] (STORE 0)
  9471.                         (let ((n (second (car rechts))))
  9472.                           (if (eql n 1)
  9473.                             (unless (and (consp (cdr rechts)) (equal (cadr rechts) '(LOAD 0)))
  9474.                               ; (LOAD 0) (SKIP 1) (PUSH) wird anders behandelt
  9475.                               (ersetze2 '(STORE 0))
  9476.                             )
  9477.                             (progn (setf (car rechts) `(SKIP ,(- n 1)))
  9478.                                    (ersetze1 '(STORE 0))
  9479.                   ) ) ) ) ) )
  9480.                   (MV-TO-STACK ; Regel 5
  9481.                     (when (gethash (first (car rechts)) one-value-ops nil)
  9482.                       ; (car rechts) liefert nur einen Wert -->
  9483.                       ; (MV-TO-STACK) durch (PUSH) ersetzen:
  9484.                       (ersetze1 '(PUSH))
  9485.                     )
  9486.                     (case (first (car rechts))
  9487.                       ((VALUES0 STACK-TO-MV) (streiche2))
  9488.                   ) )
  9489.                   (NV-TO-STACK ; Regel 5
  9490.                     (let ((n (second (car mitte))))
  9491.                       (case (first (car rechts))
  9492.                         (STACK-TO-MV
  9493.                           (let ((m (second (car rechts))))
  9494.                             (cond ((> n m) (ersetze2 `(PUSH-NIL ,(- n m))))
  9495.                                   ((< n m) (ersetze2 `(SKIP ,(- m n))))
  9496.                                   (t (streiche2))
  9497.                         ) ) )
  9498.                         ((VALUES0 NIL) (ersetze2 `(PUSH-NIL ,n)))
  9499.                         (t (when (gethash (first (car rechts)) one-value-ops nil)
  9500.                              (erweitere2 `(PUSH) `(PUSH-NIL ,(- n 1)))
  9501.                   ) ) ) )  )
  9502.                   (PUSH-UNBOUND ; Regel 6
  9503.                     (case (first (car rechts))
  9504.                       (PUSH-UNBOUND ; (PUSH-UNBOUND n) (PUSH-UNBOUND m) --> (PUSH-UNBOUND n+m)
  9505.                         (let ((n (second (car rechts)))
  9506.                               (m (second (car mitte))))
  9507.                           (ersetze2 `(PUSH-UNBOUND ,(+ n m)))
  9508.                   ) ) ) )
  9509.                   (LIST* ; Regel 7
  9510.                     (when (equal (rest (car mitte)) '(1))
  9511.                       (ersetze1 '(CONS))
  9512.                   ) )
  9513.             ) ) )
  9514.             (when (atom mitte) (return))
  9515.             ; Neues for-value berechnen, in Abhängigkeit von (car mitte):
  9516.             (setq for-value
  9517.               (gethash (first (car mitte)) for-value-table for-value)
  9518.             )
  9519.             ; weiterrücken:
  9520.             (setq links mitte mitte rechts)
  9521.           )
  9522.           ; Codestück zu Ende: (atom mitte)
  9523.           (when mitte
  9524.             ; mitte ist das Anfangslabel
  9525.             (let ((old-for-value (get mitte 'for-value)))
  9526.               ; Ist for-value besser als old-for-value ?
  9527.               (when (and (not (eq for-value old-for-value))
  9528.                          (or (eq old-for-value 'ALL) (eq for-value 'NIL))
  9529.                     )
  9530.                 ; ja -> Anfangslabel nachher als Ergebnis bringen:
  9531.                 (setf (get mitte 'for-value) for-value result mitte)
  9532.           ) ) )
  9533.         ) ; end let*
  9534.         (unless modified (return))
  9535.     ) ) ; end let, loop
  9536.     (let (codelistr)
  9537.       (when (and (eq (first (first codelist)) 'RET)
  9538.                  (consp (setq codelistr (cdr codelist)))
  9539.                  (or (eq (first (first codelistr)) 'JSR)
  9540.                      (and (eq (first (second codelist)) 'SKIP)
  9541.                           (consp (setq codelistr (cddr codelist)))
  9542.                           (eq (first (first codelistr)) 'JSR)
  9543.             )    )   )
  9544.         ; (JSR n label) [(SKIP m)] (RET) --> (JMPTAIL n n+m label)
  9545.         (let ((n (second (first codelistr)))
  9546.               (label (third (first codelistr)))
  9547.               (m (if (eq codelistr (cdr codelist)) 0 (second (second codelist)))))
  9548.           (setf (first codelist) `(JMPTAIL ,n ,(+ n m) ,label))
  9549.         )
  9550.         (remove-references (first codelistr)) ; (JSR ...) wird gestrichen
  9551.         (note-references (first codelist)) ; (JMPTAIL ...) wird eingefügt
  9552.         (setf (cdr codelist) (cdr codelistr)) ; ein bzw. zwei Listenelemente streichen
  9553.         (setq for-value-at-end 'NIL) ; JMPTAIL braucht keine Werte
  9554.     ) )
  9555.     result
  9556. ) )
  9557.  
  9558. #|
  9559.                             3. Schritt:
  9560.                       Allgemeine Optimierungen
  9561.  
  9562. Wird eine Optimierung erfolgreich durchgeführt, so werden alle weiteren
  9563. Optimierungen nochmal probiert, die sich deswegen ergeben könnten.
  9564.  
  9565. optimize-part    - ruft den 2. Schritt auf:
  9566.                    Peephole-Optimierung normaler Operationen.
  9567.  
  9568. optimize-label   - Codestücke zu Labels, die nicht (mehr) referenziert werden,
  9569.                    werden entfernt.
  9570.                  - Wird ein Label nur von einem einzigen JMP referenziert,
  9571.                    der nicht vom selben Codestück kommt, können die beiden
  9572.                    betroffenen Stücke aneinandergehängt werden.
  9573.  
  9574. optimize-short   - Liegt ein Codestück vor, wo auf das Anfangslabel label1
  9575.                    sofort ein (JMP label2) folgt, so werden alle Referenzen
  9576.                    von label1 durch label2 ersetzt und das Codestück entfernt.
  9577.                  - Liegt ein Codestück vor, wo auf das Anfangslabel label
  9578.                    sofort ein
  9579.                    (JMPCASE/JMPCASE1-TRUE/JMPCASE1-FALSE label_true label_false)
  9580.                    folgt, so können Referenzen (JMPCASE1-TRUE label l) und
  9581.                    (JMPCASE1-FALSE l label) vereinfacht werden.
  9582.                  - Ein kurzes Codestück wird direkt an zugehörige JMPs auf
  9583.                    sein Anfangslabel angehängt. (Ein Codestück heißt "kurz",
  9584.                    wenn es höchstens 2 Befehle umfaßt und nicht mit einem
  9585.                    JMPHASH (den man nicht duplizieren sollte) abgeschlossen
  9586.                    ist.)
  9587.  
  9588. optimize-jmpcase - (JMPCASE label label) wird vereinfacht zu (JMP label).
  9589.                  - (NOT) [...] (JMPCASE label_true label_false) wird
  9590.                    vereinfacht zu [...] (JMPCASE label_false label_true),
  9591.                    wobei [...] nur Befehle enthalten darf, die den 1. Wert
  9592.                    nicht verändern, und bei label_true und label_false keine
  9593.                    Werte gebraucht werden.
  9594.  
  9595. optimize-value   - Ein Wegsprung JMPCASE1-TRUE/JMPCASE1-FALSE kann durch
  9596.                    JMPCASE ersetzt werden, wenn am Ziel-Label der Wert
  9597.                    nicht gebraucht oder nur der 1. Wert gebraucht wird.
  9598.                  - Ein Wegsprung JMPCASE/JMPCASE1-TRUE/JMPCASE1-FALSE kann
  9599.                    durch ein JMP ersetzt werden, wenn der aktuelle Wert an
  9600.                    dieser Stelle als =NIL oder als /=NIL nachgewiesen werden
  9601.                    kann.
  9602.                  - Ein JMP kann die Information, welcher Wert gerade vorliegt,
  9603.                    zu seinem Ziel-Label weitertragen.
  9604.  
  9605. coalesce         - Lege Codeteile mit gleichem Ende (mind. 3 Befehle) zusammen.
  9606.  
  9607. |#
  9608.  
  9609. (defun optimize-part (code)
  9610.   (let ((label (simplify code)))
  9611.     (when label
  9612.       ; Die Property for-value von label wurde verbessert.
  9613.       (dolist (ref (symbol-value label))
  9614.         (when (integerp ref) (optimize-value ref))
  9615. ) ) ) )
  9616.  
  9617. (defun optimize-label (label &optional (index (get label 'code-part))
  9618.                                        (code (aref *code-parts* index))
  9619.                                        (lastc (last code))
  9620.                       )
  9621.   (unless (eq label (cdr lastc)) (compiler-error 'optimize-label))
  9622.   (when label
  9623.     ; label ist ein Label, es beginnt den Code
  9624.     ; code = (aref *code-parts* index), und es ist lastc = (last code).
  9625.     (let ((refs (symbol-value label))) ; Liste der Referenzen darauf
  9626.       (cond ((null refs)
  9627.               ; nicht referenziertes Label: Codestück entfernen,
  9628.               ; Referenzen aus diesem Codestück heraus eliminieren.
  9629.               (let ((labellist '())) ; Liste von Labels, die Referenzen
  9630.                                      ; verloren haben
  9631.                 (loop
  9632.                   (when (atom code) (return))
  9633.                   (setq labellist
  9634.                     (nreconc labellist (remove-references (pop code) index))
  9635.                 ) )
  9636.                 (setf (aref *code-parts* index) nil) ; Codestück entfernen
  9637.                 ; Bei Labels mit weniger Referenzen weiteroptimieren:
  9638.                 ; (Vorsicht: Hierdurch kann sich *code-parts* verändern.)
  9639.                 (dolist (olabel labellist)
  9640.                   (let* ((oindex (get olabel 'code-part))
  9641.                          (ocode (aref *code-parts* oindex)))
  9642.                     (when ocode
  9643.                       (optimize-label olabel oindex ocode)
  9644.                 ) ) )
  9645.             ) )
  9646.             ((null (cdr refs))
  9647.               ; Label mit nur einer Referenz, und zwar durch JMP ?
  9648.               (let ((ref (first refs)))
  9649.                 (when (and (integerp ref) ; Ein JMP ist ein Wegsprung
  9650.                            (eq (first (car (aref *code-parts* ref))) 'JMP)
  9651.                            (not (eql index ref)) ; aus anderem Codestück
  9652.                       )
  9653.                   ; Anhängen:
  9654.                   ; (aref *code-parts* ref) wird in die Schublade
  9655.                   ; (aref *code-parts* index) gesteckt.
  9656.                   (setf (cdr lastc) (rest (aref *code-parts* ref)))
  9657.                   (setf (aref *code-parts* ref) nil)
  9658.                   (let ((new-startlabel (cdr (last lastc)))) ; neues Startlabel von (aref *code-parts* index)
  9659.                     (when new-startlabel
  9660.                       (setf (get new-startlabel 'code-part) index)
  9661.                   ) )
  9662.                   (setf (symbol-value label) '()) ; altes Startlabel von (aref *code-parts* index) deaktivieren
  9663.                   ; neues Codestück vereinfachen:
  9664.                   (optimize-part code)
  9665. ) ) ) )     ) ) )
  9666.  
  9667. (defun optimize-short (index &optional (code (aref *code-parts* index))
  9668.                              &aux      (lastc (last code))
  9669.                                        (label (cdr lastc))
  9670.                       )
  9671.   (when label
  9672.     ; label ist ein Label, es beginnt den Code
  9673.     ; code = (aref *code-parts* index), und es ist lastc = (last code).
  9674.     (when (eq code lastc)
  9675.       ; Eine einzige Operation nach dem Label.
  9676.       (let ((item (car code)))
  9677.         (case (first item)
  9678.           (JMP ; (JMP ...) sofort nach dem Label
  9679.             (let ((to-label (second item)))
  9680.               (unless (eq label to-label)
  9681.                 (label-subst label to-label) ; Referenzen umbiegen
  9682.                 (setf (aref *code-parts* index) nil) ; Codestück entfernen
  9683.                 (setf (symbol-value to-label)
  9684.                       (delete index (symbol-value to-label)) ; Referenz fällt weg
  9685.                 )
  9686.                 (optimize-label to-label) ; mögliche Optimierung
  9687.             ) )
  9688.             (return-from optimize-short)
  9689.           )
  9690.           ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9691.             (let ((true-label (second item))
  9692.                   (false-label (third item)))
  9693.               (unless (or (eq label true-label) (eq label false-label))
  9694.                 (macrolet ((err () `(compiler-error 'optimize-short)))
  9695.                   ; JMPCASE1-Referenzen auf label vereinfachen:
  9696.                   (let ((modified-indices '())) ; Indizes von modifizierten Codestücken
  9697.                     (dolist (refindex (symbol-value label))
  9698.                       (when (integerp refindex)
  9699.                         (let* ((refcode (aref *code-parts* refindex))
  9700.                                (ref (car refcode)))
  9701.                           (case (first ref)
  9702.                             (JMP
  9703.                               ; (JMP label) --> (JMPCASE/... true-label false-label)
  9704.                               (setf (car refcode) item)
  9705.                               ; neue Verweise auf true-label und false-label:
  9706.                               (push refindex (symbol-value true-label))
  9707.                               (push refindex (symbol-value false-label))
  9708.                               (push refindex modified-indices)
  9709.                             )
  9710.                             ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9711.                               ; (JMPCASE/... label1 label2)
  9712.                               (let ((label1 (second ref)) ; im TRUE-Fall: wohin springen
  9713.                                     (label2 (third ref)) ; im FALSE-Fall: wohin springen
  9714.                                     (1-true (eq (first ref) 'JMPCASE1-TRUE)) ; im TRUE-Fall: mit (VALUES1) ?
  9715.                                     (1-false (eq (first ref) 'JMPCASE1-FALSE))) ; im FALSE-Fall: mit (VALUES1) ?
  9716.                                 (when (eq label label1)
  9717.                                   ; Der (JMPCASE/... label ...) wird vereinfacht zu
  9718.                                   ; (JMPCASE/... true-label ...).
  9719.                                   (setq label1 true-label)
  9720.                                   ; neuer Verweis auf true-label:
  9721.                                   (push refindex (symbol-value true-label))
  9722.                                   (push refindex modified-indices)
  9723.                                   (when (eq (first item) 'JMPCASE1-TRUE)
  9724.                                     (setq 1-true t)
  9725.                                 ) )
  9726.                                 (when (eq label label2)
  9727.                                   ; Der (JMPCASE/... ... label) wird vereinfacht zu
  9728.                                   ; (JMPCASE/... ... false-label).
  9729.                                   (setq label2 false-label)
  9730.                                   ; neuer Verweis auf false-label:
  9731.                                   (push refindex (symbol-value false-label))
  9732.                                   (push refindex modified-indices)
  9733.                                   (when (eq (first item) 'JMPCASE1-FALSE)
  9734.                                     (setq 1-false t)
  9735.                                 ) )
  9736.                                 (unless (eq (get label1 'for-value) 'ALL)
  9737.                                   (setq 1-true nil)
  9738.                                 )
  9739.                                 (unless (eq (get label2 'for-value) 'ALL)
  9740.                                   (setq 1-false nil)
  9741.                                 )
  9742.                                 (when (and 1-true 1-false)
  9743.                                   (push '(VALUES1) (cdr refcode))
  9744.                                   (setq 1-true nil 1-false nil)
  9745.                                 )
  9746.                                 (setf (car refcode)
  9747.                                   `(,(cond (1-true 'JMPCASE1-TRUE)
  9748.                                            (1-false 'JMPCASE1-FALSE)
  9749.                                            (t 'JMPCASE)
  9750.                                      )
  9751.                                     ,label1
  9752.                                     ,label2
  9753.                                    )
  9754.                             ) ) )
  9755.                             (JMPHASH (err)) ; JMPHASH hat undefinierte Werte
  9756.                         ) )
  9757.                         ; später:
  9758.                         ; (setf (symbol-value label) (delete refindex (symbol-value label)))
  9759.                     ) )
  9760.                     (setf (symbol-value label)
  9761.                           (delete-if #'integerp (symbol-value label))
  9762.                     )
  9763.                     ; evtl. Optimierung wegen verringerter Referenzen möglich:
  9764.                     (optimize-label label)
  9765.                     ; evtl. weitere Optimierung in veränderten Codeteilen:
  9766.                     (dolist (refindex modified-indices)
  9767.                       (simplify (aref *code-parts* refindex))
  9768.                       (optimize-value refindex)
  9769.                       (optimize-jmpcase refindex (aref *code-parts* refindex))
  9770.                     )
  9771.           ) ) ) ) )
  9772.     ) ) )
  9773.     ; Sonstige "kurze" Codestücke, maximal 2 Operationen lang:
  9774.     (when (and (or (eq code lastc) (eq (cdr code) lastc))
  9775.                (not (eq (first (car code)) 'JMPHASH))
  9776.           )
  9777.       (let ((indices '())) ; Liste der Indizes der Codestücke, an die wir code anhängen
  9778.         (setf (cdr lastc) '()) ; code vorläufig ohne das Label am Schluß
  9779.         (dolist (refindex (symbol-value label))
  9780.           (when (and (integerp refindex) (not (eql refindex index)))
  9781.             (let ((refcode (aref *code-parts* refindex)))
  9782.               (when (eq (first (car refcode)) 'JMP)
  9783.                 ; anhängen:
  9784.                 (let ((new-code (mapcar #'copy-list code)))
  9785.                   (dolist (op new-code) (note-references op refindex))
  9786.                   (setf (aref *code-parts* refindex) (nconc new-code (cdr refcode)))
  9787.                 )
  9788.                 (setf (symbol-value label) (delete refindex (symbol-value label)))
  9789.                 (push refindex indices)
  9790.         ) ) ) )
  9791.         (setf (cdr lastc) label) ; wieder das Label ans Listenende setzen
  9792.         (when indices
  9793.           ; mögliche weitere Optimierungen:
  9794.           (dolist (refindex indices)
  9795.             (optimize-part (aref *code-parts* refindex))
  9796.           )
  9797.           (optimize-label label) ; label hat weniger Referenzen -> optimieren
  9798.     ) ) )
  9799. ) )
  9800.  
  9801. ; get-boolean-value versucht zu einem Anfangsstück eines Codestücks
  9802. ; (einem (nthcdr n codelist) mit n>=1) zu bestimmen, welcher boolesche Wert
  9803. ; nach seiner Ausführung vorliegt:
  9804. ; FALSE     sicher A0 = NIL,
  9805. ; TRUE      sicher A0 /= NIL,
  9806. ; NIL       keine Aussage.
  9807. (defun get-boolean-value (code)
  9808.   (macrolet ((err () `(compiler-error 'get-boolean-value)))
  9809.     (let ((invert nil)) ; ob von hier bis zum Ende der boolesche Wert invertiert wird
  9810.       ((lambda (value)
  9811.          (if invert
  9812.            (case value (TRUE 'FALSE) (FALSE 'TRUE) (t NIL))
  9813.            value
  9814.        ) )
  9815.        (block value
  9816.          (loop ; Codeliste durchlaufen
  9817.            (when (atom code) (return))
  9818.            (case (first (car code))
  9819.              ((NIL VALUES0 TAGBODY-CLOSE-NIL) ; produzieren Wert NIL
  9820.                (return-from value 'FALSE) ; Damit können wir die Schleife abbrechen
  9821.              )
  9822.              ((T CONST CONS LIST LIST*) ; produzieren Wert /= NIL
  9823.                ; (CONST n), weil 1. man davon ausgehen kann, daß der Wert
  9824.                ; schon zur Compile-Zeit bekannt ist (siehe c-constantp und
  9825.                ; c-constant-value) und 2. die Konstante NIL in
  9826.                ; make-const-code bereits speziell behandelt wurde.
  9827.                ; (LIST n) und (LIST* n) wegen n>0.
  9828.                (return-from value 'TRUE) ; Damit können wir die Schleife abbrechen
  9829.              )
  9830.              (NOT (setq invert (not invert))) ; invertiere später den booleschen Wert
  9831.              ((UNBIND1 SKIP SKIPI SKIPSP STORE STOREI STOREV STOREC STOREIC SETVALUE
  9832.                VALUES1 BLOCK-CLOSE TAGBODY-CLOSE CATCH-CLOSE UNWIND-PROTECT-CLEANUP
  9833.              )) ; keine Änderung des 1. Werts -> weiter in der Codeliste
  9834.              (t (return-from value nil))
  9835.            )
  9836.            (setq code (cdr code))
  9837.          )
  9838.          (when code
  9839.            ; code ist das Anfangslabel.
  9840.            ; Inspiziere alle Sprünge auf das Label code:
  9841.            (let ((bisher nil))
  9842.              ; bisher = FALSE, falls bisher alle Sprünge den booleschen Wert
  9843.              ;                 FALSE mitbringen,
  9844.              ; bisher = TRUE, falls bisher alle Sprünge den booleschen Wert
  9845.              ;                TRUE mitbringen,
  9846.              ; bisher = NIL am Anfang.
  9847.              ; Falls ein Sprung einen unbekannten booleschen Wert mitbringt,
  9848.              ; kann man die Schleife gleich verlassen.
  9849.              (flet ((neu (value)
  9850.                       (cond ((null bisher) (setq bisher value))
  9851.                             ((not (eq value bisher)) (return-from value nil))
  9852.                    )) )
  9853.                (dolist (ref (symbol-value code))
  9854.                  (if (integerp ref)
  9855.                    (let ((refcode (first (aref *code-parts* ref)))) ; der Wegsprung hierher
  9856.                      ; Ein Wegsprung mit undefinierten Werten kann das nicht sein.
  9857.                      (case (first refcode)
  9858.                        (JMP
  9859.                          (if (third refcode)
  9860.                            ; Wert vor dem Sprung bekannt
  9861.                            (neu (third refcode))
  9862.                            ; Wert vor dem Sprung unbekannt
  9863.                            (return-from value nil)
  9864.                        ) )
  9865.                        ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9866.                          (when (eq code (second refcode)) (neu 'TRUE))
  9867.                          (when (eq code (third refcode)) (neu 'FALSE))
  9868.                        )
  9869.                        (t (err)) ; JMPHASH hat undefinierte Werte, und die
  9870.                                  ; anderen Wegsprünge enthalten keine Labels.
  9871.                    ) )
  9872.                    (case (first ref)
  9873.                      ((JMPIFBOUNDP BLOCK-OPEN CATCH-OPEN)
  9874.                        (return-from value nil) ; Da können wir nichts aussagen
  9875.                      )
  9876.                      (t (err)) ; An den Labels in TAGBODY-OPEN, JSR,
  9877.                                ; UNWIND-PROTECT-OPEN, UNWIND-PROTECT-CLOSE
  9878.                                ; liegen undefinierte Werte vor.
  9879.          ) ) ) ) ) )
  9880.          nil ; Default: nichts aussagbar
  9881.       ))
  9882. ) ) )
  9883.  
  9884. (defun optimize-jmpcase (index code)
  9885.   (when (eq (first (car code)) 'JMPCASE)
  9886.     ; Code endet mit (JMPCASE ...)
  9887.     (let ((true-label (second (car code)))
  9888.           (false-label (third (car code))))
  9889.       (if (eq true-label false-label)
  9890.         ; (JMPCASE label label) --> (JMP label ..)
  9891.         (progn
  9892.           (setf (car code) `(JMP ,true-label ,(get-boolean-value (cdr code))))
  9893.           ; doppelte Referenz wird zu einer einfachen:
  9894.           (setf (symbol-value true-label)
  9895.                 (delete index (symbol-value true-label) :count 1)
  9896.           )
  9897.           ; und weiter optimieren:
  9898.           (optimize-part code)
  9899.           (optimize-short (get true-label 'code-part))
  9900.         )
  9901.         (when (and (null (get true-label 'for-value))
  9902.                    (null (get false-label 'for-value))
  9903.               )
  9904.           ; Versuche NOTs zu eliminieren:
  9905.           (let ((invert 0)
  9906.                 (cr1 code)
  9907.                 (cr2 (cdr code))) ; stets cr2 = (cdr cr1)
  9908.             (loop
  9909.               (when (atom cr2) (return))
  9910.               (case (first (car cr2))
  9911.                 ((UNBIND1 SKIP SKIPI SKIPSP VALUES1 BLOCK-CLOSE TAGBODY-CLOSE
  9912.                   CATCH-CLOSE UNWIND-PROTECT-CLEANUP
  9913.                  ) ; diese Operationen brauchen keine Werte und lassen
  9914.                    ; den 1. Wert unverändert
  9915.                  (shiftf cr1 cr2 (cdr cr2))
  9916.                 )
  9917.                 (NOT
  9918.                   (setf (cdr cr1) (setq cr2 (cdr cr2))) ; (NOT) streichen
  9919.                   (incf invert)
  9920.                 )
  9921.                 (t (return))
  9922.             ) )
  9923.             ; invert = Anzahl, wie oft (NOT) gestrichen wurde
  9924.             (when (oddp invert)
  9925.               ; true-label und false-label vertauschen:
  9926.               (setf (car code) `(JMPCASE ,false-label ,true-label))
  9927.             )
  9928.             (when (plusp invert)
  9929.               ; und weiter optimieren:
  9930.               (optimize-part code)
  9931.               (optimize-short index)
  9932.         ) ) )
  9933. ) ) ) )
  9934.  
  9935. (defun optimize-value (index &optional (code (aref *code-parts* index)))
  9936.   (let ((item (car code)))
  9937.     (case (first item)
  9938.       ((JMPCASE JMPCASE1-TRUE JMPCASE1-FALSE)
  9939.         ; (JMPCASE/... true-label false-label)
  9940.         (let ((true-label (second item))
  9941.               (false-label (third item)))
  9942.           (when (or (and (eq (first item) 'JMPCASE1-TRUE)
  9943.                          (not (eq (get true-label 'for-value) 'ALL))
  9944.                          ; Wertezahl 1 wird bei true-label nicht gebraucht
  9945.                          ; (JMPCASE1-TRUE ...) --> (JMPCASE ...)
  9946.                     )
  9947.                     (and (eq (first item) 'JMPCASE1-FALSE)
  9948.                          (not (eq (get false-label 'for-value) 'ALL))
  9949.                          ; Wertezahl 1 wird bei false-label nicht gebraucht
  9950.                          ; (JMPCASE1-FALSE ...) --> (JMPCASE ...)
  9951.                 )   )
  9952.             (setq item (setf (car code) `(JMPCASE ,@(rest item))))
  9953.             ; Weitere mögliche Optimierungen:
  9954.             (optimize-jmpcase index code)
  9955.           )
  9956.           ; Versuche, den booleschen Wert an dieser Stelle zu ermitteln
  9957.           ; und vereinfache gegebenenfalls:
  9958.           (case (get-boolean-value (cdr code))
  9959.             (TRUE ; Sprung geht immer auf true-label
  9960.               ; Referenz auf false-label streichen:
  9961.               (setf (symbol-value false-label)
  9962.                 (delete index (symbol-value false-label))
  9963.               )
  9964.               (setf (car code) `(JMP ,true-label TRUE))
  9965.               (when (eq (first item) 'JMPCASE1-TRUE)
  9966.                 (push '(VALUES1) (cdr code))
  9967.                 (simplify code)
  9968.               )
  9969.               (optimize-part code) ; weitere mögliche Optimierung
  9970.               ; weitere mögliche Optimierungen:
  9971.               (optimize-label false-label) ; wegen verringerter Referenzen
  9972.               (optimize-short index) ; wegen obigem optimize-part
  9973.             )
  9974.             (FALSE
  9975.               ; Referenz auf true-label streichen
  9976.               (setf (symbol-value true-label)
  9977.                 (delete index (symbol-value true-label))
  9978.               )
  9979.               (setf (car code) `(JMP ,false-label FALSE))
  9980.               (when (eq (first item) 'JMPCASE1-FALSE)
  9981.                 (push '(VALUES1) (cdr code))
  9982.                 (simplify code)
  9983.               )
  9984.               (optimize-part code) ; weitere mögliche Optimierung
  9985.               ; weitere mögliche Optimierungen:
  9986.               (optimize-label true-label) ; wegen verringerter Referenzen
  9987.               (optimize-short index) ; wegen obigem optimize-part
  9988.       ) ) ) )
  9989.       (JMP
  9990.         (let ((label (second item)))
  9991.           (when (get label 'for-value)
  9992.             ; Wert wird benötigt
  9993.             (when (null (third item))
  9994.               ; aber er ist unbekannt.
  9995.               ; Vielleicht läßt sich der Wert herausbekommen ?
  9996.               (let ((value (get-boolean-value (cdr code))))
  9997.                 (when value
  9998.                   (setf (car code) `(JMP ,label ,value))
  9999.                   ; Wert jetzt bekannt, läßt sich vielleicht verwenden:
  10000.                   (optimize-value (get label 'code-part))
  10001. ) ) ) ) ) ) ) ) )
  10002.  
  10003. ; coalesce legt gleiche Codeteile in den gegebenen Codestücken soweit wie
  10004. ; möglich zusammen und liefert als Ergebnis ein Flag, ob etwas geändert wurde.
  10005. (defun coalesce (&optional (indexlist
  10006.                              ; Liste aller möglichen Indizes
  10007.                              (let ((L '()))
  10008.                                (dotimes (i (fill-pointer *code-parts*)) (push i L))
  10009.                                (nreverse L)
  10010.                 )          ) )
  10011.   (let ((parts-ht ; Eine Hashtabelle, die eine Abbildung realisiert:
  10012.                   ; Codeende --> Liste aller Indizes von Codestücken,
  10013.                   ;              die damit enden
  10014.           (let ((ht (make-hash-table :test #'equal :size (length indexlist))))
  10015.             (dolist (index indexlist)
  10016.               (let ((code (aref *code-parts* index))) ; ein Codestück
  10017.                 ; Wegen der Vereinfachungsregel für "kurze" Codestücke werden
  10018.                 ; nur Teile zusammengelegt, die in mindestens den letzten 3
  10019.                 ; Operationen übereinstimmen.
  10020.                 (when (and (consp code) (consp (cdr code)) (consp (cddr code)))
  10021.                   (push index
  10022.                     (gethash (list* (first code) (second code) (third code))
  10023.                              ht '()
  10024.                   ) )
  10025.             ) ) )
  10026.             ht
  10027.         ) )
  10028.         (modified nil))
  10029.     ; Dann über die möglichen Codeenden iterieren:
  10030.     (maphash
  10031.       #'(lambda (code-beginning indices)
  10032.           (declare (ignore code-beginning))
  10033.           (when (cdr indices) ; mindestens zwei Indizes mit diesem Codeende?
  10034.             ; Versuche, möglichst langes Codestück zusammenzulegen:
  10035.             (let ((codes ; Liste der zusammenzulegenden Codestücke
  10036.                     (mapcar #'(lambda (i) (aref *code-parts* i)) indices)
  10037.                   )
  10038.                   (new-code '()) ; hier wird der gemeinsame Code gesammelt
  10039.                   (new-index (fill-pointer *code-parts*)) ; Index dafür
  10040.                   (new-order ; das gemeinsame Stück wird beim letzten Teil einzusortiert
  10041.                     (reduce #'max (mapcar #'(lambda (i) (aref *code-positions* i)) indices))
  10042.                  ))
  10043.               (loop
  10044.                 ; stimmen noch alle überein?
  10045.                 (unless (every #'consp codes) (return))
  10046.                 (let* ((code1 (first codes)) ; ein beliebiges der Codestücke
  10047.                        (code11 (car code1))) ; dessen letzte Operation
  10048.                   (unless (every #'(lambda (code) (equal (car code) code11))
  10049.                                  (rest codes)
  10050.                           )
  10051.                     (return)
  10052.                   )
  10053.                   ; ja. Alle Codestücke aus codes um eine Operation verkürzen:
  10054.                   (mapc #'(lambda (code index) ; Referenzen löschen
  10055.                             (remove-references (car code) index)
  10056.                           )
  10057.                         codes indices
  10058.                   )
  10059.                   ; verkürzen: (setq codes (mapcar #'cdr codes)), oder:
  10060.                   (mapl #'(lambda (codesr)
  10061.                             (setf (car codesr) (cdr (car codesr)))
  10062.                           )
  10063.                         codes
  10064.                   )
  10065.                   (push code11 new-code) ; new-code verlängern
  10066.                   (note-references code11 new-index)
  10067.               ) )
  10068.               (let* ((new-label (make-label 'ALL))
  10069.                      ; Alle Codestücke aus codes wurden verkürzt, sie werden
  10070.                      ; jetzt verlängert um ein (JMP new-label NIL).
  10071.                      (jmpop `(JMP ,new-label NIL)))
  10072.                 (mapc #'(lambda (code index)
  10073.                           (setf (aref *code-parts* index) (cons jmpop code))
  10074.                         )
  10075.                       codes indices
  10076.                 )
  10077.                 (setf (symbol-value new-label) indices) ; Referenzen auf new-label
  10078.                 (setf (get new-label 'code-part) new-index)
  10079.                 (vector-push-extend (nreconc new-code new-label) *code-parts*)
  10080.                 (vector-push-extend new-order *code-positions*)
  10081.               )
  10082.               ; weitere mögliche Optimierungen:
  10083.               (optimize-part (aref *code-parts* new-index))
  10084.               (coalesce indices)
  10085.               (setq modified t) ; Veränderung hat stattgefunden
  10086.         ) ) )
  10087.       parts-ht
  10088.     )
  10089.     modified
  10090. ) )
  10091.  
  10092. ; Die Hauptfunktion des 3. Schritts:
  10093. ; Führt alle Optimierungen durch, und faßt dann alle Codestücke wieder zu
  10094. ; einer einzigen Codeliste zusammen und liefert diese.
  10095. (defun optimize-all ()
  10096.   ; Optimierungen:
  10097.   (loop
  10098.     ; Optimierungen aufrufen:
  10099.     ; Wird eine fündig, so ruft sie auch gleich die Optimierungs-
  10100.     ; schritte auf, die sich dadurch ergeben könnten. Daher brauchen
  10101.     ; sie hier nur einmal aufgeführt zu werden.
  10102.     ; Vorsicht hier: durch die Optimierungen können *code-parts* und sein
  10103.     ; Inhalt sich völlig verändern.
  10104.     (do ((index 0 (1+ index)))
  10105.         ((eql index (fill-pointer *code-parts*)))
  10106.       (let ((code (aref *code-parts* index)))
  10107.         (when code
  10108.           (let* ((lastc (last code))
  10109.                  (label (cdr lastc)))
  10110.             (when label
  10111.               (unless (eql index (get label 'code-part))
  10112.                 (compiler-error 'optimize-all 'code-part)
  10113.             ) )
  10114.             (optimize-label label index code lastc)
  10115.       ) ) )
  10116.       (let ((code (aref *code-parts* index)))
  10117.         (when code
  10118.           (optimize-jmpcase index code)
  10119.       ) )
  10120.       (let ((code (aref *code-parts* index)))
  10121.         (when code
  10122.           (optimize-value index code)
  10123.       ) )
  10124.       (let ((code (aref *code-parts* index)))
  10125.         (when code
  10126.           (optimize-short index code)
  10127.     ) ) )
  10128.     (unless (coalesce) (return)) ; (coalesce) tat nichts -> fertig
  10129.   )
  10130.   ; Zu einer einzigen Codeliste zusammenfassen:
  10131.   ; (Dabei werden die Labels nun Listenelemente im Code statt nur NTHCDRs.)
  10132.   (let ((start-index 0)) ; Start-"Label" NIL beginnt Codestück Nr. 0
  10133.     ; Erst jeweils ein Codestück, das mit label anfängt, wenn möglich an ein
  10134.     ; Codestück anhängen, das mit einem JMP oder JMPCASE/... zu label endet.
  10135.     (do ((index (fill-pointer *code-parts*)))
  10136.         ((eql (decf index) 0)) ; index durchläuft die Indizes von *code-parts*
  10137.                                ; von oben nach unten, ausgenommen start-index=0.
  10138.       (let ((code (aref *code-parts* index)))
  10139.         (when code
  10140.           (loop
  10141.             ; Betrachte das Label am Ende von code, im Codestück Nr. index:
  10142.             (let* ((lastc (last code)) ; letztes Cons von code
  10143.                    (label (cdr lastc)) ; Label am Ende von code
  10144.                    (refs (symbol-value label)) ; Referenzen darauf
  10145.                    (pos (aref *code-positions* index)) ; Position von code
  10146.                    (jmp-ref nil) ; bisher beste gefundene JMP-Referenz auf label
  10147.                    (jmpcase-ref nil) ; bisher beste gefundene JMPCASE-Referenz auf label
  10148.                    (jmpcase1-ref nil)) ; bisher beste gefundene JMPCASE1-...-Referenz auf label
  10149.               (if (null label)
  10150.                 ; Das Start-Code-Stück wurde umgehängt!
  10151.                 (progn
  10152.                   (setq start-index index)
  10153.                   (return) ; zum nächsten Index
  10154.                 )
  10155.                 (flet ((better (new-ref old-ref)
  10156.                          ; Eine Referenz new-ref ist "besser" als eine andere
  10157.                          ; old-ref, wenn sie näher dran ist. Dabei haben
  10158.                          ; Vorwärtsreferenzen generell Priorität gegenüber
  10159.                          ; Rückwärtsreferenzen.
  10160.                          (or (null old-ref) ; noch gar kein old-ref?
  10161.                              (let ((old-pos (aref *code-positions* old-ref))
  10162.                                    (new-pos (aref *code-positions* new-ref)))
  10163.                                (if (> old-pos pos) ; Habe bisher nur Rückwärtssprung?
  10164.                                  ; ja: new-pos ist besser, falls es
  10165.                                  ; < pos (Vorwärtssprung) oder
  10166.                                  ; >=pos, <=old-pos (kürzerer Rückwärtssprung) ist.
  10167.                                  (<= new-pos old-pos)
  10168.                                  ; nein: new-pos ist besser, falls es
  10169.                                  ; <=pos, >=old-pos (kürzerer Vorwärtssprung) ist.
  10170.                                  (<= old-pos new-pos pos)
  10171.                       )) )   ) )
  10172.                   (macrolet ((update (old-ref new-ref) ; zur Bestimmung des bisher Besten
  10173.                                `(when (better ,new-ref ,old-ref)
  10174.                                   (setq ,old-ref ,new-ref)
  10175.                                 )
  10176.                             ))
  10177.                     ; Bestimme die beste Referenz, an die das Codestück
  10178.                     ; gehängt werden kann:
  10179.                     (dolist (refindex refs)
  10180.                       (when (and (integerp refindex)
  10181.                                  (not (eql refindex index)) ; nicht an sich selber hängen!
  10182.                             )
  10183.                         (let ((refcode1 (car (aref *code-parts* refindex))))
  10184.                           (case (first refcode1)
  10185.                             (JMP ; mögliches Anhängen an (JMP label ...)
  10186.                               (update jmp-ref refindex)
  10187.                             )
  10188.                             (JMPCASE ; mögliches Anhängen an (JMPCASE ... label ...)
  10189.                               (update jmpcase-ref refindex)
  10190.                             )
  10191.                             (JMPCASE1-TRUE ; mögliches Anhängen an (JMPCASE1-TRUE ... label)
  10192.                               (when (eq label (third refcode1))
  10193.                                 (update jmpcase1-ref refindex)
  10194.                             ) )
  10195.                             (JMPCASE1-FALSE ; mögliches Anhängen an (JMPCASE1-FALSE label ...)
  10196.                               (when (eq label (second refcode1))
  10197.                                 (update jmpcase1-ref refindex)
  10198.                             ) )
  10199.                     ) ) ) )
  10200.                     (cond (jmp-ref ; an (JMP label) anhängen
  10201.                             (setf (cdr lastc)
  10202.                                   (cons label (cdr (aref *code-parts* jmp-ref)))
  10203.                             )
  10204.                             (setf (aref *code-parts* jmp-ref) nil)
  10205.                             (setq code lastc)
  10206.                           )
  10207.                           (jmpcase1-ref
  10208.                             (let* ((refcode (aref *code-parts* jmpcase1-ref))
  10209.                                    (refcode1 (car refcode))
  10210.                                    (jmpop
  10211.                                      (if (eq label (second refcode1))
  10212.                                        `(JMPIFNOT1 ,(third refcode1))
  10213.                                        `(JMPIF1 ,(second refcode1))
  10214.                                   )) )
  10215.                               (setf (cdr lastc) (list* label jmpop (cdr refcode)))
  10216.                               (setf (aref *code-parts* jmpcase1-ref) nil)
  10217.                               (setq code lastc)
  10218.                           ) )
  10219.                           (jmpcase-ref
  10220.                             (let* ((refcode (aref *code-parts* jmpcase-ref))
  10221.                                    (refcode1 (car refcode))
  10222.                                    (for-value (or (get (second refcode1) 'for-value)
  10223.                                                   (get (third refcode1) 'for-value)
  10224.                                    )          )
  10225.                                    (jmpop
  10226.                                      (if (eq label (second refcode1))
  10227.                                        `(JMPIFNOT ,(third refcode1) ,for-value)
  10228.                                        `(JMPIF ,(second refcode1) ,for-value)
  10229.                                   )) )
  10230.                               (setf (cdr lastc) (list* label jmpop (cdr refcode)))
  10231.                               (setf (aref *code-parts* jmpcase-ref) nil)
  10232.                               (setq code lastc)
  10233.                           ) )
  10234.                           (t ; kein Anhängen möglich
  10235.                             (return) ; zum nächsten Index
  10236.           ) ) ) ) ) )     )
  10237.     ) ) )
  10238.     ; Sicherstellen, daß das Anfangs-Stück auch an den Anfang kommt:
  10239.     ; (Das würde auch gehen, indem bei jeder der obigen Anhängungen
  10240.     ; ein (setf (aref *code-positions* index) (aref *code-positions* jmp..-ref))
  10241.     ; gemacht würde. Wieso tun wir das nicht??)
  10242.     (setf (aref *code-positions* start-index) 0)
  10243.     ; Codeliste zusammensetzen:
  10244.     (let ((code-parts (map 'list #'cons *code-parts* *code-positions*)))
  10245.       (setq code-parts (delete-if-not #'car code-parts)) ; code=nil bedeutet: gestrichen
  10246.       (setq code-parts (sort code-parts #'> :key #'cdr)) ; nach Reihenfolge sortieren
  10247.       ; Die Teile sind jetzt in der richtigen Ordnung, nur umgekehrt.
  10248.       (let ((codelist '()))
  10249.         (dolist (code-part code-parts)
  10250.           (let ((code (car code-part)))
  10251.             ; code an codelist anhängen, dabei aber den Wegsprung umwandeln:
  10252.             (let ((item (car code)))
  10253.               (case (first item)
  10254.                 (JMP (setf (car code) `(JMP ,(second item))))
  10255.                 (JMPCASE ; (JMPCASE true-label false-label)
  10256.                          ; --> (JMPIFNOT false-label fv) (JMP true-label)
  10257.                   (setq code
  10258.                     (list* `(JMP ,(second item))
  10259.                            `(JMPIFNOT ,(third item)
  10260.                                       ,(or (get (second item) 'for-value)
  10261.                                            (get (third item) 'for-value)
  10262.                                        )
  10263.                             )
  10264.                            (cdr code)
  10265.                 ) ) )
  10266.                 (JMPCASE1-TRUE ; (JMPCASE1-TRUE true-label false-label)
  10267.                                ; --> (JMPIF1 true-label) (JMP false-label)
  10268.                   (setq code
  10269.                     (list* `(JMP ,(third item))
  10270.                            `(JMPIF1 ,(second item))
  10271.                            (cdr code)
  10272.                 ) ) )
  10273.                 (JMPCASE1-FALSE ; (JMPCASE1-FALSE true-label false-label)
  10274.                                 ; --> (JMPIFNOT1 false-label) (JMP true-label)
  10275.                   (setq code
  10276.                     (list* `(JMP ,(second item))
  10277.                            `(JMPIFNOT1 ,(third item))
  10278.                            (cdr code)
  10279.             ) ) ) ) )
  10280.             ; Label zum Listenelement machen:
  10281.             (let ((lastc (last code)))
  10282.               (when (cdr lastc)
  10283.                 (setf (cdr lastc) (list (cdr lastc)))
  10284.             ) )
  10285.             ; Umdrehen und vor codelist hängen (deswegen wurde vorhin
  10286.             ; mit #'> statt #'< sortiert):
  10287.             (setq codelist (nreconc code codelist))
  10288.         ) )
  10289.         codelist
  10290. ) ) ) )
  10291.  
  10292. #| Debug-Hilfe:
  10293. (defun optimize-check ()
  10294.   (do ((index 0 (1+ index)))
  10295.       ((eql index (fill-pointer *code-parts*)))
  10296.     (let ((code (aref *code-parts* index)))
  10297.       (when code
  10298.         (let* ((lastc (last code))
  10299.                (label (cdr lastc)))
  10300.           (when label
  10301.             (unless (eql index (get label 'code-part))
  10302.               (compiler-error 'optimize-check 'code-part)
  10303. ) ) ) ) ) ) )
  10304. (trace
  10305.   (optimize-part    :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10306.   (optimize-label   :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10307.   (optimize-short   :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10308.   (optimize-jmpcase :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10309.   (optimize-value   :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10310.   (coalesce         :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10311.   (optimize-all     :pre (optimize-check) :post (optimize-check) :suppress-if t)
  10312. )
  10313. |#
  10314.  
  10315. #| Was ist mit den folgenden möglichen Optimierungen??
  10316.  
  10317. 10. Kommt vor einem (JMP label) ein (UNWIND-PROTECT-CLEANUP) und vor dem
  10318.    label ein (UNWIND-PROTECT-3 cleanup-label), so muß es sich um denselben
  10319.    UNWIND-PROTECT-Frame handeln, und man kann (UNWIND-PROTECT-CLEANUP)
  10320.    streichen und (JMP label) durch (JMP newlabel) ersetzen, wobei newlabel
  10321.    ein neues Label ist, das vor dem (evtl. zu ergänzenden) (UNWIND-PROTECT-2)
  10322.    vor cleanup-label sitzt:
  10323.    (UNWIND-PROTECT-CLEANUP) (JMP label) ...
  10324.    ... [(UNWIND-PROTECT-2)] cleanup-label ... (UNWIND-PROTECT-3 cleanup-label) label
  10325.    -->
  10326.    (JMP newlabel) ...
  10327.    ... newlabel (UNWIND-PROTECT-2) cleanup-label ... (UNWIND-PROTECT-3 cleanup-label) label
  10328.  
  10329. 11. Kommt nach einem Label label ein (NIL), so darf jeder (JMPIFNOT label)
  10330.    und jeder (JMPIFNOT1 label) durch ein (JMPIFNOT1 z) ersetzt werden,
  10331.    wo z ein neues Label nach dem (NIL) ist:
  10332.           (JMPIFNOT label) ... label (NIL) ...
  10333.    -->       (JMPIFNOT1 z) ... label (NIL) z ...
  10334.  
  10335. |#
  10336.  
  10337. ; Führt den 1. und 2.,3. Schritt aus:
  10338. (defun compile-to-LAP ()
  10339.   (let ((*code-parts* (make-array 10 :adjustable t :fill-pointer 0))
  10340.         (*code-positions* (make-array 10 :adjustable t :fill-pointer 0)))
  10341.     ; Expandiert den Code des Fnode *func* und teilt ihn in Stücke auf.
  10342.     ; Hinterläßt seine Werte in *code-parts* und *code-positions*.
  10343.     (let ((*code-part* (list '(START))) ; NIL als Start-"Label"
  10344.           (*code-index* 0)
  10345.           (*dead-code* nil)
  10346.           (*label-subst* '())
  10347.           (*current-value* nil)
  10348.           (*current-vars* '()))
  10349.       (traverse-anode (anode-code (fnode-code *func*)))
  10350.     )
  10351.     ; Optimiert in *code-parts* und *code-positions*, faßt dann den Code
  10352.     ; in einer Liste zusammen und liefert diese:
  10353.     (let ((code-list (optimize-all)))
  10354.       (unless (equal (pop code-list) '(START))
  10355.         (compiler-error 'compile-to-LAP 'start)
  10356.       )
  10357.       code-list
  10358. ) ) )
  10359.  
  10360.  
  10361. #|
  10362.                             4. Schritt:
  10363.                       Eliminieren von (CONST n)
  10364.  
  10365. Generische Funktionen haben eine feste Länge. Die Konstanten werden im
  10366. VENV-Const aufbewahrt. In diesem Schritt werden umgewandelt:
  10367.   (LOADV k m)    -->  (LOADV k+1 m)
  10368.   (STOREV k m)   -->  (STOREV k+1 m)
  10369.   (CONST n)      -->  (LOADV 0 n)
  10370.   (VENV)         -->  (LOADV 0 0)
  10371.   (JMPHASH n ht label . labels)  -->  (JMPHASHV n ht label . labels)
  10372.   (GETVALUE n)         -->  illegal
  10373.   (SETVALUE n)         -->  illegal
  10374.   (BIND n)             -->  illegal
  10375.   (COPY-CLOSURE m n)   -->  illegal
  10376.   (CALL k n)           -->  illegal
  10377.   (CALL0 n)            -->  illegal
  10378.   (CALL1 n)            -->  illegal
  10379.   (CALL2 n)            -->  illegal
  10380.   (BLOCK-OPEN n label) -->  illegal
  10381.   (RETURN-FROM n)      -->  illegal
  10382.   (GO n k)             -->  illegal
  10383. |#
  10384.  
  10385. (defun CONST-to-LOADV (code-list)
  10386.   (do ((codelistr code-list (cdr codelistr)))
  10387.       ((null codelistr))
  10388.     (let ((item (car codelistr)))
  10389.       (when (consp item)
  10390.         (case (first item)
  10391.           ((LOADV STOREV)
  10392.             (setf (car codelistr)
  10393.                   `(,(first item) ,(1+ (second item)) ,@(cddr item))
  10394.           ) )
  10395.           (CONST
  10396.             (setf (car codelistr) `(LOADV 0 ,@(cdr item)))
  10397.           )
  10398.           (VENV
  10399.             (setf (car codelistr) `(LOADV 0 0))
  10400.           )
  10401.           (JMPHASH
  10402.             (setf (car codelistr) `(JMPHASHV ,@(cdr item)))
  10403.           )
  10404.           ((GETVALUE SETVALUE BIND COPY-CLOSURE CALL CALL0 CALL1 CALL2
  10405.             BLOCK-OPEN RETURN-FROM GO)
  10406.             (compiler-error 'CONST-to-LOADV "Illegal-in-GF")
  10407.           )
  10408.   ) ) ) )
  10409.   code-list
  10410. )
  10411.  
  10412.  
  10413. #|
  10414.                             5. Schritt:
  10415.                    Bestimmung des Stackbedarfs
  10416.  
  10417. Dieser Schritt bestimmt, wieviel SP-Einträge die Funktion maximal braucht.
  10418. |#
  10419.  
  10420. #+CLISP3
  10421. (defun SP-depth (code-list)
  10422.   (let ((max-depth 0) ; bisherige Maximal-Tiefe
  10423.         (unseen-label-alist '()) ; Labels, ab denen noch verfolgt werden muß
  10424.         (seen-label-alist '()) ; Labels, die schon verfolgt wurden
  10425.           ; jeweils Aliste ((label . depth) ...)
  10426.           ; Es ist durchaus möglich, daß dasselbe Codestück mit unterschied-
  10427.           ; lichen SP-Tiefen durchgeführt werden kann (nämlich dann, wenn es
  10428.           ; mit einem Wegsprung THROW, RETURN-FROM, GO oder ERROR endet)!
  10429.           ; seen-label-alist enthält zu jedem Label die maximale Tiefe, mit
  10430.           ; der ab diesem Label schon verfolgt wurde.
  10431.           ; unsee-label-alist enthält zu jedem Label die maximale bisher
  10432.           ; notierte Tiefe, mit der ab diesem Label noch verfolgt werden muß.
  10433.         (mitte code-list) ; restliche Codeliste
  10434.         (depth 0) ; aktuelle Tiefe
  10435.        )
  10436.     (macrolet ((check-depth (wanted-depth)
  10437.                  ; überprüft, ob depth gleich der Tiefe wanted-depth ist
  10438.                  `(unless (eql depth ,wanted-depth)
  10439.                     (compiler-error 'SP-depth)
  10440.                   )
  10441.               ))
  10442.       (loop
  10443.         ; mitte läuft durch die Codeliste, von der aktuellen Position
  10444.         ; bis zum nächsten Wegsprung, und zählt die Tiefe mit.
  10445.         (loop
  10446.           (when (null mitte) (return))
  10447.           (let ((item (car mitte)))
  10448.             (if (atom item)
  10449.               ; Label
  10450.               (let ((h (assoc item seen-label-alist)))
  10451.                 (if h
  10452.                   (if (<= depth (cdr h)) (return) (setf (cdr h) depth))
  10453.                   (push (cons item depth) seen-label-alist)
  10454.               ) )
  10455.               ; Instruktion
  10456.               (macrolet ((note-label (labelform)
  10457.                            ; notiere, daß zu label gesprungen werden kann
  10458.                            (let ((label (gensym)))
  10459.                              `(let* ((,label ,labelform)
  10460.                                      (h (assoc ,label seen-label-alist)))
  10461.                                 (unless (and h (<= depth (cdr h)))
  10462.                                   (setq h (assoc ,label unseen-label-alist))
  10463.                                   (if h
  10464.                                     (unless (<= depth (cdr h)) (setf (cdr h) depth))
  10465.                                     (push (cons ,label depth) unseen-label-alist)
  10466.                               ) ) )
  10467.                          ) )
  10468.                          (note-inc (amount)
  10469.                            ; notiere, daß depth um amount erhöht wird
  10470.                            `(progn
  10471.                               (incf depth ,amount)
  10472.                               (when (> depth max-depth) (setq max-depth depth))
  10473.                             )
  10474.                          )
  10475.                          (note-dec (amount)
  10476.                            ; notiere, daß depth um amount erniedrigt wird
  10477.                            `(progn
  10478.                               (decf depth ,amount)
  10479.                               (when (minusp depth) (compiler-error 'SP-depth "<0"))
  10480.                             )
  10481.                          )
  10482.                          (note-jmp ()
  10483.                            ; notiere, daß weggesprungen wird
  10484.                            `(return)
  10485.                         ))
  10486.                 (case (first item)
  10487.                   (JMP ; (JMP label)
  10488.                     (note-label (second item))
  10489.                     (note-jmp)
  10490.                   )
  10491.                   ((JMPIF JMPIF1 JMPIFNOT JMPIFNOT1 JMPIFBOUNDP) ; (JMP... label)
  10492.                     (note-label (second item))
  10493.                   )
  10494.                   ((JMPHASH JMPHASHV JMPTAIL) ; (JMPHASH.. n ht label . labels), (JMPTAIL m n label)
  10495.                     (dolist (label (cdddr item)) (note-label label))
  10496.                     (note-jmp)
  10497.                   )
  10498.                   (JSR ; (JSR n label)
  10499.                     (let ((depth 0)) (note-label (third item)))
  10500.                   )
  10501.                   ((THROW RETURN-FROM GO ERROR) ; (THROW), (RETURN-FROM n), (GO n k), (ERROR n)
  10502.                     (note-jmp)
  10503.                   )
  10504.                   (RET ; (RET)
  10505.                     (check-depth 0)
  10506.                     (note-jmp)
  10507.                   )
  10508.                   (PROGV ; (PROGV)
  10509.                     (note-inc 1)
  10510.                   )
  10511.                   (CATCH-OPEN ; (CATCH-OPEN label)
  10512.                     (note-label (second item))
  10513.                     (note-inc (+ 2 *jmpbuf-size*))
  10514.                   )
  10515.                   (CATCH-CLOSE ; (CATCH-CLOSE)
  10516.                     (note-dec (+ 2 *jmpbuf-size*))
  10517.                   )
  10518.                   (UNWIND-PROTECT-OPEN ; (UNWIND-PROTECT-OPEN label)
  10519.                     ; eigentlich: (note-inc (+ 2 *jmpbuf-size*))
  10520.                     (note-inc 3) (note-label (second item)) (note-dec 3)
  10521.                     (note-inc (+ 2 *jmpbuf-size*))
  10522.                   )
  10523.                   (UNWIND-PROTECT-NORMAL-EXIT ; (UNWIND-PROTECT-NORMAL-EXIT), danach kommt label
  10524.                     (note-dec (+ 2 *jmpbuf-size*)) (note-inc 3)
  10525.                   )
  10526.                   (UNWIND-PROTECT-CLOSE ; (UNWIND-PROTECT-CLOSE label)
  10527.                     ; eigentlich: (note-dec 3)
  10528.                     (note-label (second item)) (note-dec 3)
  10529.                   )
  10530.                   (UNWIND-PROTECT-CLEANUP ; (UNWIND-PROTECT-CLEANUP)
  10531.                     ; eigentlich: (note-dec (+ 2 *jmpbuf-size*)) (note-inc 3) ... (note-dec 3)
  10532.                     (note-dec (+ 2 *jmpbuf-size*))
  10533.                   )
  10534.                   (BLOCK-OPEN ; (BLOCK-OPEN n label)
  10535.                     (note-label (third item))
  10536.                     (note-inc (+ 2 *jmpbuf-size*))
  10537.                   )
  10538.                   (BLOCK-CLOSE ; (BLOCK-CLOSE)
  10539.                     (note-dec (+ 2 *jmpbuf-size*))
  10540.                   )
  10541.                   (TAGBODY-OPEN ; (TAGBODY-OPEN m label1 ... labelm)
  10542.                     (note-inc (+ 1 *jmpbuf-size*))
  10543.                     (dolist (label (cddr item)) (note-label label))
  10544.                   )
  10545.                   ((TAGBODY-CLOSE-NIL TAGBODY-CLOSE) ; (TAGBODY-CLOSE-NIL), (TAGBODY-CLOSE)
  10546.                     (note-dec (+ 1 *jmpbuf-size*))
  10547.                   )
  10548.                   (MVCALLP ; (MVCALLP)
  10549.                     (note-inc 1)
  10550.                   )
  10551.                   (MVCALL ; (MVCALL)
  10552.                     (note-dec 1)
  10553.                   )
  10554.                   (SKIPSP ; (SKIPSP k)
  10555.                     (note-dec (second item))
  10556.                   )
  10557.                   (SKIPI ; (SKIPI k n)
  10558.                     (note-dec (+ (second item) 1))
  10559.                   )
  10560.               ) )
  10561.           ) )
  10562.           (setq mitte (cdr mitte))
  10563.         )
  10564.         ; Nächstes zu verfolgendes Label suchen:
  10565.         (loop
  10566.           (when (null unseen-label-alist) ; fertig ?
  10567.             (return-from SP-depth max-depth)
  10568.           )
  10569.           (let* ((unseen (pop unseen-label-alist)) ; nächstes zu verfolgendes
  10570.                  (label (car unseen))) ; Label
  10571.             (setq depth (cdr unseen))
  10572.             (let ((h (assoc label seen-label-alist)))
  10573.               (unless (and h (<= depth (cdr h)))
  10574.                 ; Ab diesem Label die Codeliste abarbeiten:
  10575.                 ; (Dadurch wird (label . depth) in seen-label-alist aufgenommen,
  10576.                 ; es ist bereits aus unseen-label-alist entfernt.)
  10577.                 (setq mitte (member label code-list :test #'eq))
  10578.                 (return)
  10579.         ) ) ) )
  10580. ) ) ) )
  10581.  
  10582.  
  10583. #|
  10584.                             6. Schritt:
  10585.                  Einführung von Kurz-Operationen
  10586.  
  10587. Dieser Schritt arbeitet auf der Codeliste und verändert sie dabei destruktiv.
  10588.  
  10589. 1. (ATOM) (JMPIF label NIL)             --> (JMPIFATOM label)
  10590.    (ATOM) (JMPIFNOT label NIL)          --> (JMPIFCONSP label)
  10591.    (CONSP) (JMPIF label NIL)            --> (JMPIFCONSP label)
  10592.    (CONSP) (JMPIFNOT label NIL)         --> (JMPIFATOM label)
  10593.    (ATOM)                               --> (PUSH) (CALLS ATOM)
  10594.    (CONSP)                              --> (PUSH) (CALLS CONSP)
  10595.  
  10596. 2. (NIL) (PUSH)                         --> (NIL&PUSH)
  10597.    (NIL) (PUSH) ... (NIL) (PUSH)        --> (PUSH-NIL n)
  10598.    (NIL) (STORE n)                      --> (NIL&STORE n)
  10599.    (PUSH-NIL 1)                         --> (NIL&PUSH)
  10600.  
  10601. 3. (T) (PUSH)                           --> (T&PUSH)
  10602.    (T) (STORE n)                        --> (T&STORE n)
  10603.  
  10604. 4. (CONST n) (PUSH)                     --> (CONST&PUSH n)
  10605.    (CONST n) (SYMBOL-FUNCTION) (PUSH)   --> (CONST&SYMBOL-FUNCTION&PUSH n)
  10606.    (CONST n) (SYMBOL-FUNCTION) (STORE m)--> (CONST&SYMBOL-FUNCTION&STORE n m)
  10607.    (CONST n) (SYMBOL-FUNCTION)          --> (CONST&SYMBOL-FUNCTION n)
  10608.  
  10609. 5. (COPY-CLOSURE n m) (PUSH)            --> (COPY-CLOSURE&PUSH n m)
  10610.  
  10611. 6. (LOAD n) (PUSH)                      --> (LOAD&PUSH n)
  10612.    (LOAD k) (STOREC n m)                --> (LOAD&STOREC k n m)
  10613.    (LOAD n) (JMPIF label fv)            --> (LOAD&JMPIF n label)
  10614.    (LOAD n) (JMPIFNOT label fv)         --> (LOAD&JMPIFNOT n label)
  10615.    (LOAD n) (CAR) (PUSH)                --> (LOAD&CAR&PUSH n)
  10616.    (LOAD n) (CDR) (PUSH)                --> (LOAD&CDR&PUSH n)
  10617.    (LOAD n) (CDR) (STORE n)             --> (LOAD&CDR&STORE n)
  10618.    (LOAD n+1) (CONS) (STORE n)          --> (LOAD&CONS&STORE n)
  10619.    (LOAD n) (PUSH) (CALLS 1+) (STORE n) --> (LOAD&INC&STORE n)
  10620.    (LOAD n) (PUSH) (CALLS 1-) (STORE n) --> (LOAD&DEC&STORE n)
  10621.    (LOAD n) (PUSH) (CALLS 1+) (PUSH)    --> (LOAD&INC&PUSH n)
  10622.    (LOAD n) (PUSH) (CALLS 1-) (PUSH)    --> (LOAD&DEC&PUSH n)
  10623.    (LOAD n) (CAR) (STORE m)             --> (LOAD&CAR&STORE n m)
  10624.  
  10625. 7. (JMPIFBOUNDP n l) (NIL) (STORE n) l  --> (UNBOUND->NIL n) l
  10626.  
  10627. 8. (LOADI n1 n2) (PUSH)                 --> (LOADI&PUSH n1 n2)
  10628.    (LOADC n1 n2) (PUSH)                 --> (LOADC&PUSH n1 n2)
  10629.    (LOADV n1 n2) (PUSH)                 --> (LOADV&PUSH n1 n2)
  10630.  
  10631. 9. (GETVALUE n) (PUSH)                  --> (GETVALUE&PUSH n)
  10632.  
  10633. 10. (UNBIND1) ... (UNBIND1)             --> (UNBIND n)
  10634.  
  10635. 11. (CAR) (PUSH)                        --> (CAR&PUSH)
  10636.     (CDR) (PUSH)                        --> (CDR&PUSH)
  10637.     (CONS) (PUSH)                       --> (CONS&PUSH)
  10638.     (LIST n) (PUSH)                     --> (LIST&PUSH n)
  10639.     (LIST* n) (PUSH)                    --> (LIST*&PUSH n)
  10640.     (FUNCALL n) (PUS)                   --> (FUNCALL&PUSH n)
  10641.     (APPLY n) (PUSH)                    --> (APPLY&PUSH n)
  10642.  
  10643. 12. (POP) (STORE n)                      --> (POP&STORE n)
  10644.  
  10645. 13. (SKIP n) (RET)                      --> (SKIP&RET n)
  10646.     ; (RET)                             --> (SKIP&RET 0)
  10647.     ; kommt nicht vor, da im Stack stets noch die Closure selbst sitzt
  10648.  
  10649. 14. (UNWIND-PROTECT-CLOSE label)        --> (UNWIND-PROTECT-CLOSE)
  10650.  
  10651. 15. (JMPHASH n ht label . labels)       --> (JMPHASH n ht label)
  10652.     (JMPHASHV n ht label . labels)      --> (JMPHASHV n ht label)
  10653.  
  10654. 16. (JSR n label)                       --> (JSR label)
  10655.     (JSR n label) (PUSH)                --> (JSR&PUSH label)
  10656.  
  10657. 17. (CALL m n) (PUSH)                   --> (CALL&PUSH m n)
  10658.     (CALL1 n) (PUSH)                    --> (CALL1&PUSH n)
  10659.     (CALL2 n) (PUSH)                    --> (CALL2&PUSH n)
  10660.     (CALLS1 n) (PUSH)                   --> (CALLS1&PUSH n)
  10661.     (CALLS2 n) (PUSH)                   --> (CALLS2&PUSH n)
  10662.     (CALLSR m n) (PUSH)                 --> (CALLSR&PUSH m n)
  10663.     (CALLC) (PUSH)                      --> (CALLC&PUSH)
  10664.     (CALLCKEY) (PUSH)                   --> (CALLCKEY&PUSH)
  10665.  
  10666. 18. (CALL1 n) (JMPIF label fv)          --> (CALL1&JMPIF n label)
  10667.     (CALL1 n) (JMPIFNOT label fv)       --> (CALL1&JMPIFNOT n label)
  10668.     (CALL2 n) (JMPIF label fv)          --> (CALL2&JMPIF n label)
  10669.     (CALL2 n) (JMPIFNOT label fv)       --> (CALL2&JMPIFNOT n label)
  10670.     (CALLS1 n) (JMPIF label fv)         --> (CALLS1&JMPIF n label)
  10671.     (CALLS1 n) (JMPIFNOT label fv)      --> (CALLS1&JMPIFNOT n label)
  10672.     (CALLS2 n) (JMPIF label fv)         --> (CALLS2&JMPIF n label)
  10673.     (CALLS2 n) (JMPIFNOT label fv)      --> (CALLS2&JMPIFNOT n label)
  10674.     (CALLSR m n) (JMPIF label fv)       --> (CALLSR&JMPIF m n label)
  10675.     (CALLSR m n) (JMPIFNOT label fv)    --> (CALLSR&JMPIFNOT m n label)
  10676.  
  10677. 19. (CALLS1 n) (STORE k)                --> (CALLS1&STORE n k)
  10678.     (CALLS2 n) (STORE k)                --> (CALLS2&STORE n k)
  10679.     (CALLSR m n) (STORE k)              --> (CALLSR&STORE m n k)
  10680.  
  10681. 20. (EQ) (JMPIF label NIL)              --> (JMPIFEQ label)
  10682.     (EQ) (JMPIFNOT label NIL)           --> (JMPIFNOTEQ label)
  10683.     (CONST n) (EQ) (JMPIF label NIL)    --> (JMPIFEQTO n label)
  10684.     (CONST n) (EQ) (JMPIFNOT label NIL) --> (JMPIFNOTEQTO n label)
  10685.  
  10686. 21. (APPLY n) (SKIP k) (RET)            --> (APPLY&SKIP&RET n k)
  10687.  
  10688. |#
  10689.  
  10690. (let ((CALLS-1+ (CALLS-code (gethash '1+ function-codes)))
  10691.       (CALLS-1- (CALLS-code (gethash '1- function-codes)))
  10692.       (CALLS-atom (CALLS-code (gethash 'atom function-codes)))
  10693.       (CALLS-consp (CALLS-code (gethash 'consp function-codes))))
  10694.   (defun insert-combined-LAPs (code-list)
  10695.     ; Zunächst die ATOM/CONSP-Umwandlung, weil diese PUSHs einführen kann:
  10696.     (do ((crest code-list (cdr crest)))
  10697.         ((null crest))
  10698.       (let ((item (car crest)))
  10699.         (when (and (consp item)
  10700.                    (memq (setq item (first item)) '(ATOM CONSP))
  10701.               )
  10702.           (if (and #| (consp (cdr crest)) |#
  10703.                    (consp (cadr crest))
  10704.                    (memq (first (cadr crest)) '(JMPIF JMPIFNOT))
  10705.                    (null (third (cadr crest)))
  10706.               )
  10707.             ; z.B. (ATOM) (JMPIF label NIL) --> (JMPIFATOM label)
  10708.             (setf (car crest)
  10709.                   `(,(if (eq (first (cadr crest)) 'JMPIF)
  10710.                        (if (eq item 'ATOM) 'JMPIFATOM 'JMPIFCONSP)
  10711.                        (if (eq item 'ATOM) 'JMPIFCONSP 'JMPIFATOM)
  10712.                      )
  10713.                     ,(second (cadr crest))
  10714.                    )
  10715.                   (cdr crest) (cddr crest)
  10716.             )
  10717.             ; z.B. (ATOM) --> (PUSH) (CALLS ATOM)
  10718.             (setf (car crest) '(PUSH)
  10719.                   (cdr crest) (cons (if (eq item 'ATOM) CALLS-atom CALLS-consp)
  10720.                                     (cdr crest)
  10721.             )                 )
  10722.     ) ) ) )
  10723.     ; Nun die sonstigen Umformungen: Ein einziger Durchlauf.
  10724.     ; Zwei Pointer laufen durch die Codeliste: ...mitte.rechts...
  10725.     (do* ((mitte code-list rechts)
  10726.           (rechts (cdr mitte) (cdr rechts)))
  10727.          ((null mitte))
  10728.       (macrolet ((ersetze (length new-code)
  10729.                    ; ersetzt die nächsten length Elemente
  10730.                    ; (nth 0 mitte) ... (nth (- length 1) mitte)
  10731.                    ; durch ein einziges Element new-code.
  10732.                    (assert (typep length '(INTEGER 0 4)))
  10733.                    `(progn
  10734.                       ,(case length
  10735.                          (0 `(setf (cdr mitte) (setq rechts (cons (car mitte) rechts))
  10736.                                    (car mitte) ,new-code
  10737.                          )   )
  10738.                          (1 `(setf (car mitte) ,new-code))
  10739.                          (t `(setf (car mitte) ,new-code
  10740.                                    (cdr mitte) ,(setq rechts
  10741.                                                   (case length
  10742.                                                     (2 `(cdr rechts))
  10743.                                                     (3 `(cddr rechts))
  10744.                                                     (4 `(cdddr rechts))
  10745.                                                 ) )
  10746.                        ) )   )
  10747.                       (go weiter)
  10748.                     )
  10749.                 ))
  10750.         (let ((item (car mitte)))
  10751.           (when (consp item)
  10752.             ; Untersuchung des Befehls item und der nachfolgenden:
  10753.             (when (and #| (consp rechts) |# (consp (car rechts)))
  10754.               ; normale Umwandlungen, mit Aneinanderhängen der Argumente:
  10755.               (let ((new-op
  10756.                       (cdr (assoc (first item)
  10757.                                   (case (first (car rechts))
  10758.                                     (PUSH  '((T        . T&PUSH)
  10759.                                              (CONST    . CONST&PUSH)
  10760.                                              (LOADI    . LOADI&PUSH)
  10761.                                              (LOADC    . LOADC&PUSH)
  10762.                                              (LOADV    . LOADV&PUSH)
  10763.                                              (GETVALUE . GETVALUE&PUSH)
  10764.                                              (CALL     . CALL&PUSH)
  10765.                                              (CALL1    . CALL1&PUSH)
  10766.                                              (CALL2    . CALL2&PUSH)
  10767.                                              (CALLS1   . CALLS1&PUSH)
  10768.                                              (CALLS2   . CALLS2&PUSH)
  10769.                                              (CALLSR   . CALLSR&PUSH)
  10770.                                              (CALLC    . CALLC&PUSH)
  10771.                                              (CALLCKEY . CALLCKEY&PUSH)
  10772.                                              (CAR      . CAR&PUSH)
  10773.                                              (CDR      . CDR&PUSH)
  10774.                                              (CONS     . CONS&PUSH)
  10775.                                              (LIST     . LIST&PUSH)
  10776.                                              (LIST*    . LIST*&PUSH)
  10777.                                              (FUNCALL  . FUNCALL&PUSH)
  10778.                                              (APPLY    . APPLY&PUSH)
  10779.                                              (COPY-CLOSURE . COPY-CLOSURE&PUSH)
  10780.                                     )       )
  10781.                                     (JMPIF
  10782.                                       (let ((alist
  10783.                                               '((EQ     . JMPIFEQ)
  10784.                                                 (LOAD   . LOAD&JMPIF)
  10785.                                                 (CALL1  . CALL1&JMPIF)
  10786.                                                 (CALL2  . CALL2&JMPIF)
  10787.                                                 (CALLS1 . CALLS1&JMPIF)
  10788.                                                 (CALLS2 . CALLS2&JMPIF)
  10789.                                                 (CALLSR . CALLSR&JMPIF)
  10790.                                                )
  10791.                                            ))
  10792.                                         (when (third (car rechts))
  10793.                                           (setq alist (cdr alist))
  10794.                                         )
  10795.                                         (setf (cddr (car rechts)) '())
  10796.                                         alist
  10797.                                     ) )
  10798.                                     (JMPIFNOT
  10799.                                       (let ((alist
  10800.                                               '((EQ     . JMPIFNOTEQ)
  10801.                                                 (LOAD   . LOAD&JMPIFNOT)
  10802.                                                 (CALL1  . CALL1&JMPIFNOT)
  10803.                                                 (CALL2  . CALL2&JMPIFNOT)
  10804.                                                 (CALLS1 . CALLS1&JMPIFNOT)
  10805.                                                 (CALLS2 . CALLS2&JMPIFNOT)
  10806.                                                 (CALLSR . CALLSR&JMPIFNOT)
  10807.                                                )
  10808.                                            ))
  10809.                                         (when (third (car rechts))
  10810.                                           (setq alist (cdr alist))
  10811.                                         )
  10812.                                         (setf (cddr (car rechts)) '())
  10813.                                         alist
  10814.                                     ) )
  10815.                                     (STORE '((NIL    . NIL&STORE)
  10816.                                              (T      . T&STORE)
  10817.                                              (POP    . POP&STORE)
  10818.                                              (CALLS1 . CALLS1&STORE)
  10819.                                              (CALLS2 . CALLS2&STORE)
  10820.                                              (CALLSR . CALLSR&STORE)
  10821.                                     )       )
  10822.                                     (STOREC '((LOAD . LOAD&STOREC)))
  10823.                                     (RET '((SKIP . SKIP&RET)))
  10824.                                   )
  10825.                                   :test #'eq
  10826.                    )) )    )
  10827.                 (when new-op
  10828.                   (ersetze 2 `(,new-op ,@(rest item) ,@(rest (car rechts))))
  10829.             ) ) )
  10830.             ; weitere Umwandlungen:
  10831.             (case (first item)
  10832.               ((NIL PUSH-NIL)
  10833.                 (flet ((nilpusher-p (coder)
  10834.                          ; Kommt (NIL) (PUSH) --> 1,
  10835.                          ; kommt (PUSH-NIL n) --> n,
  10836.                          ; sonst nil.
  10837.                          (and #| (consp coder) |# (consp (car coder))
  10838.                               (case (first (car coder))
  10839.                                 (PUSH-NIL (second (car coder)))
  10840.                                 ((NIL) (when (equal (cadr coder) '(PUSH))
  10841.                                          (setf (cdr coder) (cddr coder))
  10842.                                          1
  10843.                                 )      )
  10844.                                 (t nil)
  10845.                       )) )    )
  10846.                   (let ((count (nilpusher-p mitte)))
  10847.                     (when count
  10848.                       (setq rechts (cdr mitte))
  10849.                       (loop
  10850.                         (let ((next-count (nilpusher-p rechts)))
  10851.                           (unless next-count (return))
  10852.                           (incf count next-count)
  10853.                         )
  10854.                         (setq rechts (cdr rechts))
  10855.                       )
  10856.                       (setf (car mitte) (if (eql count 1) '(NIL&PUSH) `(PUSH-NIL ,count))
  10857.                             (cdr mitte) rechts
  10858.                       )
  10859.                       (go weiter)
  10860.               ) ) ) )
  10861.               (CONST
  10862.                 (when (and #| (consp rechts) |# (consp (car rechts)))
  10863.                   (case (first (car rechts))
  10864.                     (SYMBOL-FUNCTION
  10865.                       (let ((n (second item)))
  10866.                         (cond ((and #| (consp (cdr rechts)) |#
  10867.                                     (equal (cadr rechts) '(PUSH))
  10868.                                )
  10869.                                (ersetze 3 `(CONST&SYMBOL-FUNCTION&PUSH ,n))
  10870.                               )
  10871.                               ((and #| (consp (cdr rechts)) |#
  10872.                                     (consp (cadr rechts))
  10873.                                     (eq (first (cadr rechts)) 'STORE)
  10874.                                )
  10875.                                (ersetze 3
  10876.                                  `(CONST&SYMBOL-FUNCTION&STORE ,n ,(second (cadr rechts)))
  10877.                               ))
  10878.                               (t (ersetze 2 `(CONST&SYMBOL-FUNCTION ,n)))
  10879.                     ) ) )
  10880.                     (EQ
  10881.                       (when (and #| (consp (cdr rechts)) |#
  10882.                                  (consp (cadr rechts))
  10883.                                  (memq (first (cadr rechts)) '(JMPIF JMPIFNOT))
  10884.                                  (null (third (cadr rechts)))
  10885.                             )
  10886.                         (ersetze 3
  10887.                           `(,(if (eq (first (cadr rechts)) 'JMPIF)
  10888.                                'JMPIFEQTO
  10889.                                'JMPIFNOTEQTO
  10890.                              )
  10891.                             ,(second item)
  10892.                             ,(second (cadr rechts))
  10893.                            )
  10894.               ) ) ) ) ) )
  10895.               (LOAD
  10896.                 (when (and #| (consp rechts) |# (consp (car rechts)))
  10897.                   (let ((n (second item)))
  10898.                     (case (first (car rechts))
  10899.                       (CAR
  10900.                         (when (and #| (consp (cdr rechts)) |# (consp (cadr rechts)))
  10901.                           (case (first (cadr rechts))
  10902.                             (PUSH (ersetze 3 `(LOAD&CAR&PUSH ,n)))
  10903.                             (STORE
  10904.                               (ersetze 3
  10905.                                 `(LOAD&CAR&STORE ,n ,(second (cadr rechts)))
  10906.                       ) ) ) ) )
  10907.                       (CDR
  10908.                         (when (and #| (consp (cdr rechts)) |# (consp (cadr rechts)))
  10909.                           (case (first (cadr rechts))
  10910.                             (PUSH (ersetze 3 `(LOAD&CDR&PUSH ,n)))
  10911.                             (STORE
  10912.                               (when (eql n (second (cadr rechts)))
  10913.                                 (ersetze 3 `(LOAD&CDR&STORE ,n))
  10914.                       ) ) ) ) )
  10915.                       (CONS
  10916.                         (when (and #| (consp (cdr rechts)) |# (consp (cadr rechts))
  10917.                                    (eq (first (cadr rechts)) 'STORE)
  10918.                                    (eql (second (cadr rechts)) (- n 1))
  10919.                               )
  10920.                           (ersetze 3 `(LOAD&CONS&STORE ,(- n 1)))
  10921.                       ) )
  10922.                       (PUSH
  10923.                         (when (and #| (consp (cdr rechts)) |# (consp (cadr rechts))
  10924.                                    (or (equal (cadr rechts) CALLS-1+)
  10925.                                        (equal (cadr rechts) CALLS-1-)
  10926.                                    )
  10927.                                    #| (consp (cddr rechts)) |# (consp (caddr rechts))
  10928.                               )
  10929.                           (when (equal (caddr rechts) '(PUSH))
  10930.                             (ersetze 4
  10931.                               `(,(if (equal (cadr rechts) CALLS-1+)
  10932.                                    'LOAD&INC&PUSH
  10933.                                    'LOAD&DEC&PUSH
  10934.                                  )
  10935.                                 ,n
  10936.                                )
  10937.                           ) )
  10938.                           (when (and (eq (first (caddr rechts)) 'STORE)
  10939.                                      (eql (second (caddr rechts)) n)
  10940.                                 )
  10941.                             (ersetze 4
  10942.                               `(,(if (equal (cadr rechts) CALLS-1+)
  10943.                                    'LOAD&INC&STORE
  10944.                                    'LOAD&DEC&STORE
  10945.                                  )
  10946.                                 ,n
  10947.                                )
  10948.                         ) ) )
  10949.                         (ersetze 2 `(LOAD&PUSH ,n))
  10950.               ) ) ) ) )
  10951.               (JMPIFBOUNDP ; vereinfache (JMPIFBOUNDP n l) (NIL) (STORE n) l
  10952.                 (when (and #| (consp rechts) |#
  10953.                            (equal (car rechts) '(NIL))
  10954.                            #| (consp (cdr rechts)) |#
  10955.                            (consp (cadr rechts))
  10956.                            (eq (first (cadr rechts)) 'STORE)
  10957.                            (eql (second (cadr rechts)) (second item))
  10958.                            #| (consp (cddr rechts)) |#
  10959.                            (eq (caddr rechts) (third item))
  10960.                       )
  10961.                   (ersetze 3 `(UNBOUND->NIL ,(second item)))
  10962.               ) )
  10963.               (JSR
  10964.                 (if (and #| (consp rechts) |# (equal (car rechts) '(PUSH)))
  10965.                   (ersetze 2 `(JSR&PUSH ,(third item)))
  10966.                   (ersetze 1 `(JSR ,(third item)))
  10967.               ) )
  10968.               (UNBIND1
  10969.                 (let ((count 1))
  10970.                   (loop
  10971.                     (unless (and #| (consp rechts) |#
  10972.                                  (equal (car rechts) '(UNBIND1))
  10973.                             )
  10974.                       (return)
  10975.                     )
  10976.                     (incf count)
  10977.                     (setq rechts (cdr rechts))
  10978.                   )
  10979.                   (unless (eql count 1)
  10980.                     (setf (car mitte) `(UNBIND ,count))
  10981.                     (setf (cdr mitte) rechts)
  10982.                     (go weiter)
  10983.               ) ) )
  10984.               ;(RET (ersetze 1 '(SKIP&RET 0))) ; kommt nicht vor!
  10985.               (UNWIND-PROTECT-CLOSE (ersetze 1 '(UNWIND-PROTECT-CLOSE)))
  10986.               ((JMPIF JMPIFNOT) (ersetze 1 `(,(first item) ,(second item))))
  10987.               ((JMPHASH JMPHASHV)
  10988.                 (let ((hashtable (third item))
  10989.                       (labels (cddddr item)))
  10990.                   (maphash
  10991.                     #'(lambda (obj index) ; (gethash obj hashtable) = index
  10992.                         (setf (gethash obj hashtable) (nth index labels))
  10993.                       )
  10994.                     hashtable
  10995.                 ) )
  10996.                 (setf (cddddr (car mitte)) '())
  10997.               )
  10998.               (APPLY
  10999.                 (when (and #| (consp rechts) |#
  11000.                            (consp (car rechts))
  11001.                            (eq (first (car rechts)) 'SKIP)
  11002.                            #| (consp (cdr rechts)) |#
  11003.                            (equal (cadr rechts) '(RET))
  11004.                       )
  11005.                   (ersetze 3 `(APPLY&SKIP&RET ,(second item) ,(second (car rechts))))
  11006.               ) )
  11007.       ) ) ) )
  11008.       weiter ; Hier ist man mit (car mitte) fertig.
  11009.     )
  11010.     code-list
  11011.   )
  11012. )
  11013.  
  11014.  
  11015. #|
  11016.                                 7. Schritt:
  11017.                 Umwandlung der Instruktionen in eine Byte-Folge
  11018.  
  11019. Erster Teilschritt: jeder Instruktion wird eine Klassifikation der Instruktion
  11020. und die Länge der Instruktion (Label-Operanden nicht mitgezählt)
  11021. vorangestellt, jedem Label wird sein PC als Wert zugewiesen.
  11022. Dabei werden die Operandenlängen - soweit möglich - bestimmt, in Instruktionen
  11023. auftretende Labels werden durch (vermutliche Verweislänge . label) ersetzt.
  11024. So wird aus (BLOCK-OPEN 2 #:G7) --> (NL 2 . (67 2 (1 . #:G7))) .
  11025. Weitere Teilschritte:
  11026. Immer wieder wird die Codeliste durchlaufen, dabei werden Sprungverweise
  11027. eventuell von 1 auf 2 oder 6 Byte verlängert. Dadurch kann der Code insgesamt
  11028. nur länger werden.
  11029. Letzter Teilschritt:
  11030. Die Sprungverweise werden in Distanzen umgesetzt, und die Codeliste wird
  11031. als Liste von Bytes neu aufgebaut.
  11032. |#
  11033. ; gibt an, wieviel Bytes ein numerischer Operand braucht:
  11034. (defun num-operand-length (n)
  11035.   (cond ((< n 128) 1) ; 7 Bit in 1 Byte
  11036.         ((< n 32768) 2) ; 15 Bit in 2 Bytes
  11037.         (t 6) ; sonst 6 Bytes
  11038. ) )
  11039. ; assembliert eine Code-Liste und liefert eine Bytecode-Liste:
  11040. (defun assemble-LAP (code-list)
  11041.   ; erster Teilschritt:
  11042.   (do ((code-listr code-list (cdr code-listr))
  11043.        (PC 0))
  11044.       ((null code-listr))
  11045.     (let ((item (car code-listr)))
  11046.       (if (atom item)
  11047.         (setf (symbol-value item) PC)
  11048.         (let ((instr-code (gethash (first item) instruction-codes)))
  11049.           (unless instr-code (compiler-error 'assemble-LAP "ILLEGAL INSTRUCTION"))
  11050.           (let ((instr-class (second (svref instruction-table instr-code)))
  11051.                 (instr-length 1))
  11052.             (if (and (eq instr-class 'K)
  11053.                      (< (second item)
  11054.                         (svref short-code-opsize (position (first item) instruction-table-K))
  11055.                 )    )
  11056.               (progn
  11057.                 (setq instr-code
  11058.                   (+ (svref short-code-ops
  11059.                             (position (first item) instruction-table-K)
  11060.                      )
  11061.                      (second item)
  11062.                 ) )
  11063.                 (setq instr-class 'O)
  11064.                 (setq item (list (first item)))
  11065.               )
  11066.               (case instr-class
  11067.                 (O)
  11068.                 ((K N) (incf instr-length (num-operand-length (second item))))
  11069.                 (B (incf instr-length 1))
  11070.                 (L (incf PC 1) (push 1 (second item)))
  11071.                 (NN (incf instr-length (num-operand-length (second item)))
  11072.                     (incf instr-length (num-operand-length (third item))) )
  11073.                 (NB (incf instr-length (num-operand-length (second item)))
  11074.                     (incf instr-length 1) )
  11075.                 (BN (incf instr-length 1)
  11076.                     (incf instr-length (num-operand-length (third item))) )
  11077.                 (NNN (incf instr-length (num-operand-length (second item)))
  11078.                      (incf instr-length (num-operand-length (third item)))
  11079.                      (incf instr-length (num-operand-length (fourth item))) )
  11080.                 (NBN (incf instr-length (num-operand-length (second item)))
  11081.                      (incf instr-length 1)
  11082.                      (incf instr-length (num-operand-length (fourth item))) )
  11083.                 (NL (incf instr-length (num-operand-length (second item)))
  11084.                     (incf PC 1) (push 1 (third item)) )
  11085.                 (BL (incf instr-length 1)
  11086.                     (incf PC 1) (push 1 (third item)) )
  11087.                 (NNL (incf instr-length (num-operand-length (second item)))
  11088.                      (incf instr-length (num-operand-length (third item)))
  11089.                      (incf PC 1) (push 1 (fourth item)) )
  11090.                 (NBL (incf instr-length (num-operand-length (second item)))
  11091.                      (incf instr-length 1)
  11092.                      (incf PC 1) (push 1 (fourth item)) )
  11093.                 (NHL (incf instr-length (num-operand-length (second item)))
  11094.                      (incf PC 1) (push 1 (fourth item)) )
  11095.                 (NLX (incf instr-length (num-operand-length (second item)))
  11096.                      (do ((L (cddr item) (cdr L)))
  11097.                          ((null L))
  11098.                        (incf PC 1) (push 1 (car L))
  11099.                 )    )
  11100.             ) )
  11101.             (incf PC instr-length)
  11102.             (setf (car code-listr)
  11103.               (list* instr-class instr-length instr-code (cdr item))
  11104.             )
  11105.   ) ) ) ) )
  11106.   ; weitere Teilschritte:
  11107.   (loop
  11108.     (unless
  11109.       (let ((modified nil) (PC 0))
  11110.         (dolist (item code-list)
  11111.           (if (atom item)
  11112.             (setf (symbol-value item) PC)
  11113.             (progn
  11114.               (incf PC (cadr item))
  11115.               (when (memq (car item) '(L NL BL NNL NBL NHL NLX))
  11116.                 (let ((itemargs (cdddr item)))
  11117.                   (dolist (x (case (car item)
  11118.                                (L itemargs)
  11119.                                ((NL BL NLX) (cdr itemargs))
  11120.                                ((NNL NBL NHL) (cddr itemargs))
  11121.                           )  )
  11122.                     (incf PC (car x))
  11123.                     (let ((new-dist (- (symbol-value (cdr x)) PC)))
  11124.                       ; bisher angenommene Sprunglänge und neu errechnete abgleichen:
  11125.                       (if (<= -64 new-dist 63) ; 7 Bits in 1 Byte
  11126.                         () ; Sprunglänge bleibt 1
  11127.                         (if (<= -16384 new-dist 16383) ; 15 Bits in 2 Bytes
  11128.                           (case (car x)
  11129.                             (1 (setf (car x) 2) ; neue Sprunglänge=2
  11130.                                (incf PC 1) ; gibt 2-1=1 Bytes Verlängerung
  11131.                                (setq modified t)
  11132.                           ) )
  11133.                           ; 32 Bits in 6 Bytes
  11134.                           (case (car x)
  11135.                             (1 (setf (car x) 6) ; neue Sprunglänge=6
  11136.                                (incf PC 5) ; gibt 6-1=5 Bytes Verlängerung
  11137.                                (setq modified t)
  11138.                             )
  11139.                             (2 (setf (car x) 6) ; neue Sprunglänge=6
  11140.                                (incf PC 4) ; gibt 6-2=4 Bytes Verlängerung
  11141.                                (setq modified t)
  11142.                       ) ) ) )
  11143.               ) ) ) )
  11144.         ) ) )
  11145.         modified
  11146.       )
  11147.       (return) ; nichts mehr verändert -> alle Sprunglängen optimal
  11148.   ) )
  11149.   ; letzter Teilschritt:
  11150.   (let ((byte-list '()) (PC 0))
  11151.     (flet ((new-byte (n) (push n byte-list)))
  11152.       (flet ((num-operand (n)
  11153.                (cond ((< n 128) (new-byte n))
  11154.                      ((< n 32768) (new-byte (+ 128 (ldb (byte 7 8) n)))
  11155.                                   (new-byte (ldb (byte 8 0) n))
  11156.                      )
  11157.                      (t (compiler-error 'assemble-LAP "15 BIT"))
  11158.              ) )
  11159.              (label-operand (x)
  11160.                (incf PC (car x))
  11161.                (let ((dist (- (symbol-value (cdr x)) PC)))
  11162.                  (case (car x)
  11163.                    (1 (new-byte (ldb (byte 7 0) dist)))
  11164.                    (2 (new-byte (+ 128 (ldb (byte 7 8) dist)))
  11165.                       (new-byte (ldb (byte 8 0) dist))
  11166.                    )
  11167.                    (6 (new-byte 128) (new-byte 0)
  11168.                       (new-byte (ldb (byte 8 24) dist))
  11169.                       (new-byte (ldb (byte 8 16) dist))
  11170.                       (new-byte (ldb (byte 8 8) dist))
  11171.                       (new-byte (ldb (byte 8 0) dist))
  11172.                  ) )
  11173.             )) )
  11174.         (dolist (item code-list)
  11175.           (when (consp item)
  11176.             (incf PC (cadr item))
  11177.             (new-byte (caddr item))
  11178.             (case (car item)
  11179.               (O) ; darin fallen auch die 1-Byte-Befehle vom Typ K
  11180.               ((K N) (num-operand (second (cddr item))))
  11181.               (B (new-byte (second (cddr item))))
  11182.               (L (label-operand (second (cddr item))))
  11183.               (NN (num-operand (second (cddr item)))
  11184.                   (num-operand (third (cddr item))) )
  11185.               (NB (num-operand (second (cddr item)))
  11186.                   (new-byte (third (cddr item))) )
  11187.               (BN (new-byte (second (cddr item)))
  11188.                   (num-operand (third (cddr item))) )
  11189.               (NNN (num-operand (second (cddr item)))
  11190.                    (num-operand (third (cddr item)))
  11191.                    (num-operand (fourth (cddr item))) )
  11192.               (NBN (num-operand (second (cddr item)))
  11193.                    (new-byte (third (cddr item)))
  11194.                    (num-operand (fourth (cddr item))) )
  11195.               (NL (num-operand (second (cddr item)))
  11196.                   (label-operand (third (cddr item))) )
  11197.               (BL (new-byte (second (cddr item)))
  11198.                   (label-operand (third (cddr item))) )
  11199.               (NNL (num-operand (second (cddr item)))
  11200.                    (num-operand (third (cddr item)))
  11201.                    (label-operand (fourth (cddr item))) )
  11202.               (NBL (num-operand (second (cddr item)))
  11203.                    (new-byte (third (cddr item)))
  11204.                    (label-operand (fourth (cddr item))) )
  11205.               (NHL (num-operand (second (cddr item)))
  11206.                    (let ((ht (third (cddr item))))
  11207.                      (maphash
  11208.                        #'(lambda (obj x) ; x = (gethash obj ht)
  11209.                            (setf (gethash obj ht) (- (symbol-value x) PC))
  11210.                          )
  11211.                        ht
  11212.                    ) )
  11213.                    (label-operand (fourth (cddr item)))
  11214.               )
  11215.               (NLX (num-operand (second (cddr item)))
  11216.                    (dolist (x (cddr (cddr item))) (label-operand x)) )
  11217.             )
  11218.         ) )
  11219.     ) )
  11220.     (nreverse byte-list)
  11221. ) )
  11222.  
  11223. ; die Umkehrung zu assemble-LAP : liefert zu einer Bytecode-Liste die dazu
  11224. ; gehörige Codeliste. In dieser steht allerdings vor jedem Item noch der PC.
  11225. (defun disassemble-LAP (byte-list const-list)
  11226.   (let ((code-list '()) (PC 0) instr-PC (label-alist '()))
  11227.     ; label-alist ist eine Liste von Conses (PC . label), in der die PCs streng
  11228.     ; fallend geordnet sind.
  11229.     (flet ((PC->label-a (PC)
  11230.              (cons PC (make-symbol
  11231.                         (concatenate 'string "L" (prin1-to-string PC))
  11232.            ) )        )
  11233.            (next-byte () (incf PC) (pop byte-list))
  11234.           )
  11235.       (flet ((num-operand ()
  11236.                (let ((a (next-byte)))
  11237.                  (cond ((< a 128) a)
  11238.                        (t (+ (* 256 (- a 128)) (next-byte)))
  11239.              ) ) )
  11240.              (label-operand
  11241.                   (&optional
  11242.                     (dist
  11243.                       (let ((a (next-byte)))
  11244.                         (cond ((< a 128) (if (< a 64) a (- a 128)))
  11245.                               (t (setq a (- a 128))
  11246.                                  (unless (< a 64) (setq a (- a 128)))
  11247.                                  (setq a (+ (* 256 a) (next-byte)))
  11248.                                  (if (zerop a)
  11249.                                    (+ (* 256 (+ (* 256 (+ (* 256 (next-byte))
  11250.                                                           (next-byte)
  11251.                                                 )      )
  11252.                                                 (next-byte)
  11253.                                       )      )
  11254.                                       (next-byte)
  11255.                                    )
  11256.                                    a
  11257.                     ) ) )     )  )
  11258.                    &aux
  11259.                     (label-PC (+ PC dist))
  11260.                   )
  11261.                ; Suche label-PC in label-alist:
  11262.                (do* ((L1 nil L2)
  11263.                      (L2 label-alist (cdr L2))) ; L1 = nil oder L2 = (cdr L1)
  11264.                     ((cond
  11265.                        ((or (null L2) (> label-PC (caar L2))) ; einfügen
  11266.                         (setq L2 (cons (PC->label-a label-PC) L2))
  11267.                         (if L1 (setf (cdr L1) L2) (setq label-alist L2))
  11268.                         t)
  11269.                        ((= label-PC (caar L2)) t)
  11270.                        (t nil)
  11271.                      )
  11272.                      (cdar L2)
  11273.             )) )    )
  11274.         (loop
  11275.           (when (null byte-list) (return))
  11276.           (setq instr-PC PC) ; PC beim Start der Instruktion
  11277.           (let ((instruction
  11278.                   (let ((instr-code (next-byte)))
  11279.                     (if (>= instr-code short-code-base)
  11280.                       (let* ((q (position instr-code short-code-ops :test #'>= :from-end t))
  11281.                              (r (- instr-code (svref short-code-ops q))))
  11282.                         (list (svref instruction-table-K q) r)
  11283.                       )
  11284.                       (let* ((table-entry (svref instruction-table instr-code))
  11285.                              (instr-name (first table-entry)))
  11286.                         (case (second table-entry)
  11287.                           (O (list instr-name))
  11288.                           ((K N) (list instr-name (num-operand)))
  11289.                           (B (list instr-name (next-byte)))
  11290.                           (L (list instr-name (label-operand)))
  11291.                           (NN (list instr-name (num-operand) (num-operand)))
  11292.                           (NB (list instr-name (num-operand) (next-byte)))
  11293.                           (BN (list instr-name (next-byte) (num-operand)))
  11294.                           (NNN (list instr-name (num-operand) (num-operand) (num-operand)))
  11295.                           (NBN (list instr-name (num-operand) (next-byte) (num-operand)))
  11296.                           (NL (list instr-name (num-operand) (label-operand)))
  11297.                           (BL (list instr-name (next-byte) (label-operand)))
  11298.                           (NNL (list instr-name (num-operand) (num-operand) (label-operand)))
  11299.                           (NBL (list instr-name (num-operand) (next-byte) (label-operand)))
  11300.                           (NHL (let* ((n (num-operand))
  11301.                                       (ht (if (eq instr-name 'JMPHASH)
  11302.                                             (nth n const-list)           ; JMPHASH
  11303.                                             (svref (first const-list) n) ; JMPHASHV
  11304.                                       )   )
  11305.                                       (labels '()))
  11306.                                  (maphash
  11307.                                    #'(lambda (obj dist)
  11308.                                        (declare (ignore obj))
  11309.                                        (push (label-operand dist) labels)
  11310.                                      )
  11311.                                    ht
  11312.                                  )
  11313.                                  (list* instr-name n (label-operand) labels)
  11314.                           )    )
  11315.                           (NLX (let ((n (num-operand))
  11316.                                      (L '()))
  11317.                                  (dotimes (i n) (push (label-operand) L))
  11318.                                  (list* instr-name n (nreverse L))
  11319.                           )    )
  11320.                )) ) ) ) )
  11321.             (push (cons instr-PC instruction) code-list)
  11322.         ) )
  11323.     ) )
  11324.     ; (setq label-alist (sort label-alist #'> :key #'car))
  11325.     ; code-list umdrehen und dabei die Labels einfügen:
  11326.     (let ((new-code-list '()))
  11327.       (loop
  11328.         (when (and new-code-list label-alist
  11329.                    (= (caar new-code-list) (caar label-alist))
  11330.               )
  11331.           (push (car label-alist) new-code-list)
  11332.           (setq label-alist (cdr label-alist))
  11333.         )
  11334.         (when (null code-list) (return))
  11335.         ; eine Instruktion von code-list in new-code-list übernehmen:
  11336.         (psetq code-list (cdr code-list)
  11337.                new-code-list (rplacd code-list new-code-list)
  11338.       ) )
  11339.       new-code-list
  11340. ) ) )
  11341.  
  11342.  
  11343. #|
  11344.                            8. Schritt:
  11345.                     funktionales Objekt bilden
  11346.  
  11347. Die Funktion make-closure wird dazu vorausgesetzt.
  11348. |#
  11349. ; trägt eine Byteliste als Code in fnode ein.
  11350. (defun create-fun-obj (fnode byte-list #+CLISP3 SPdepth)
  11351.   (setf (fnode-code fnode)
  11352.     (make-closure
  11353.       :name (fnode-name fnode)
  11354.       :codevec
  11355.         (macrolet ((as-word (anz)
  11356.                      (if *big-endian*
  11357.                        ; BIG-ENDIAN-Prozessor
  11358.                        `(floor ,anz 256)
  11359.                        ; LITTLE-ENDIAN-Prozessor
  11360.                        `(multiple-value-bind (q r) (floor ,anz 256) (values r q))
  11361.                   )) )
  11362.           (multiple-value-call #'list*
  11363.             #+CLISP3 (as-word SPdepth)
  11364.             (as-word (fnode-req-anz fnode))
  11365.             (as-word (fnode-opt-anz fnode))
  11366.             (+ (if (fnode-rest-flag fnode) 1 0)
  11367.                (if (fnode-gf-p fnode) 16 0)
  11368.                (if (fnode-keyword-flag fnode)
  11369.                  (+ 128 (if (fnode-allow-other-keys-flag fnode) 64 0))
  11370.                  0
  11371.             )  )
  11372.             (values ; Argumenttyp-Kürzel
  11373.               (let ((req-anz (fnode-req-anz fnode))
  11374.                     (opt-anz (fnode-opt-anz fnode))
  11375.                     (rest (fnode-rest-flag fnode))
  11376.                     (key (fnode-keyword-flag fnode)))
  11377.                 (cond ((and (not rest) (not key) (< (+ req-anz opt-anz) 6))
  11378.                        (+ (svref '#(1 7 12 16 19 21) opt-anz) req-anz)
  11379.                       )
  11380.                       ((and rest (not key) (zerop opt-anz) (< req-anz 5))
  11381.                        (+ 22 req-anz)
  11382.                       )
  11383.                       ((and (not rest) key (< (+ req-anz opt-anz) 5))
  11384.                        (+ (svref '#(27 32 36 39 41) opt-anz) req-anz)
  11385.                       )
  11386.                       (t 0)
  11387.             ) ) )
  11388.             (if (fnode-keyword-flag fnode)
  11389.               (multiple-value-call #'values
  11390.                 (as-word (length (fnode-keywords fnode)))
  11391.                 (as-word (fnode-Keyword-Offset fnode))
  11392.               )
  11393.               (values)
  11394.             )
  11395.             byte-list
  11396.         ) )
  11397.       :consts
  11398.         (let* ((spare-list (make-list (fnode-Keyword-Offset fnode)))
  11399.                (l (append
  11400.                     spare-list
  11401.                     (fnode-keywords fnode)
  11402.                     (if *compiling-from-file*
  11403.                       (mapcar #'(lambda (value form)
  11404.                                   (if form (make-load-time-eval form) value)
  11405.                                 )
  11406.                               (fnode-Consts fnode) (fnode-Consts-forms fnode)
  11407.                       )
  11408.                       (fnode-Consts fnode)
  11409.               ))  ) )
  11410.           (if (fnode-gf-p fnode)
  11411.             (append spare-list (list (coerce l 'simple-vector)))
  11412.             l
  11413.         ) )
  11414.   ) )
  11415.   fnode
  11416. )
  11417.  
  11418. ; Liefert die Signatur eines funktionalen Objekts,
  11419. ; als Werte:
  11420. ; 1. req-anz
  11421. ; 2. opt-anz
  11422. ; 3. rest-p
  11423. ; 4. key-p
  11424. ; 5. keyword-list
  11425. ; 6. allow-other-keys-p
  11426. ; und zusätzlich
  11427. ; 7. byte-list
  11428. ; 8. const-list
  11429. (defun signature (closure)
  11430.   (let ((const-list (closure-consts closure))
  11431.         (byte-list (closure-codevec closure)))
  11432.     (macrolet ((pop2 (listvar)
  11433.                  (if *big-endian*
  11434.                    ; BIG-ENDIAN-Prozessor
  11435.                    `(+ (* 256 (pop ,listvar)) (pop ,listvar))
  11436.                    ; LITTLE-ENDIAN-Prozessor
  11437.                    `(+ (pop ,listvar) (* 256 (pop ,listvar)))
  11438.               )) )
  11439.       #+CLISP3 (progn (pop byte-list) (pop byte-list))
  11440.       (let* ((req-anz (pop2 byte-list))
  11441.              (opt-anz (pop2 byte-list))
  11442.              (h (pop byte-list))
  11443.              (key-p (logbitp 7 h)))
  11444.         (pop byte-list)
  11445.         (values
  11446.           req-anz
  11447.           opt-anz
  11448.           (logbitp 0 h)
  11449.           key-p
  11450.           (when key-p
  11451.             (let ((kw-count (pop2 byte-list))
  11452.                   (kw-offset (pop2 byte-list)))
  11453.               (subseq (if (logbitp 4 h) ; generische Funktion?
  11454.                         (coerce (first const-list) 'list)
  11455.                         const-list
  11456.                       )
  11457.                       kw-offset (+ kw-offset kw-count)
  11458.           ) ) )
  11459.           (logbitp 6 h)
  11460.           byte-list
  11461.           const-list
  11462. ) ) ) ) )
  11463.  
  11464.  
  11465. ;                  D R I T T E R   P A S S
  11466.  
  11467. (defun pass3 ()
  11468.   (dolist (pair *fnode-fixup-table*)
  11469.     (let ((code (fnode-code (first pair))) (n (second pair)))
  11470.       (macrolet ((closure-const (code n)
  11471.                    #-CLISP `(nth ,n (closure-consts ,code))
  11472.                    #+CLISP `(sys::%record-ref ,code (+ 2 ,n))
  11473.                 ))
  11474.         (setf (closure-const code n) (fnode-code (closure-const code n)))
  11475. ) ) ) )
  11476.  
  11477.  
  11478. ;             T O P - L E V E L - A U F R U F
  11479.  
  11480. ; compiliert einen Lambdabody und liefert seinen Code.
  11481. (defun compile-lambdabody (name lambdabody)
  11482.   (let ((fnode (c-lambdabody name lambdabody)))
  11483.     (unless *no-code*
  11484.       (let ((*fnode-fixup-table* '()))
  11485.         (pass2 fnode)
  11486.         (pass3)
  11487.       )
  11488.       (fnode-code fnode)
  11489. ) ) )
  11490.  
  11491. ; wird bei (lambda (...) (declare (compile)) ...) aufgerufen und liefert ein
  11492. ; zu diesem Lambda-Ausdruck äquivalentes funktionales Objekt.
  11493. (defun compile-lambda (name lambdabody %venv% %fenv% %benv% %genv% %denv%)
  11494.   (let ((*compiling* t)
  11495.         (*compiling-from-file* nil)
  11496.         (*c-listing-output* nil)
  11497.         (*c-error-output* *error-output*)
  11498.         (*known-special-vars* '())
  11499.         (*constant-special-vars* '())
  11500.         (*func* nil)
  11501.         (*fenv* %fenv%)
  11502.         (*benv* %benv%)
  11503.         (*genv* %genv%)
  11504.         (*venv* %venv%)
  11505.         (*venvc* nil)
  11506.         (*denv* %denv%)
  11507.         (*error-count* 0) (*warning-count* 0)
  11508.         (*no-code* nil)
  11509.        )
  11510.     (let ((funobj (compile-lambdabody name lambdabody)))
  11511.       (unless (zerop *error-count*)
  11512.         (return-from compile-lambda (compile-lambdabody name '(() NIL)))
  11513.       )
  11514.       funobj
  11515. ) ) )
  11516.  
  11517. ; wird bei (let/let*/multiple-value-bind ... (declare (compile)) ...) aufgerufen
  11518. ; und liefert ein funktionales Objekt, das - mit 0 Argumenten aufgerufen - diese
  11519. ; Form ausführt.
  11520. (let ((form-count 0))
  11521.   (defun compile-form (form %venv% %fenv% %benv% %genv% %denv%)
  11522.     (compile-lambda (symbol-suffix '#:COMPILED-FORM (incf form-count))
  11523.                     `(() ,form)
  11524.                     %venv% %fenv% %benv% %genv% %denv%
  11525.   ) )
  11526. )
  11527.  
  11528. ; Common-Lisp-Funktion COMPILE
  11529. #-CROSS
  11530. (defun compile (name &optional (definition nil svar)
  11531.                      &aux (macro-flag nil) (trace-flag nil))
  11532.   (unless (function-name-p name)
  11533.     (error #+DEUTSCH "Name einer zu compilierenden Funktion muß ein Symbol sein, nicht: ~S"
  11534.            #+ENGLISH "Name of function to be compiled must be a symbol, not ~S"
  11535.            name
  11536.   ) )
  11537.   (let ((symbol (get-funname-symbol name)))
  11538.     (if svar
  11539.       ; Neudefinition von name als Funktion.
  11540.       (progn
  11541.         ; Ist name getraced -> falls vorher Macro, erst untracen.
  11542.         (when (and name (setq svar (get symbol 'sys::traced-definition)))
  11543.           (if (consp svar)
  11544.             (progn
  11545.               (warn #+DEUTSCH "~S: ~S war getraced und wird umdefiniert!"
  11546.                     #+ENGLISH "~S: redefining ~S; it was traced!"
  11547.                     'compile name
  11548.               )
  11549.               (sys::untrace2 name)
  11550.             )
  11551.             (setq trace-flag t)
  11552.         ) )
  11553.         (when (compiled-function-p definition)
  11554.           (warn #+DEUTSCH "~S ist schon compiliert."
  11555.                 #+ENGLISH "~S is already compiled."
  11556.                 definition
  11557.           )
  11558.           (when name
  11559.             (if trace-flag
  11560.               (setf (get symbol 'sys::traced-definition) definition)
  11561.               (setf (symbol-function symbol) definition)
  11562.           ) )
  11563.           (return-from compile name)
  11564.       ) )
  11565.       ; Compilierung der vorhandenen Funktions-/Macro-Definition.
  11566.       (progn
  11567.         (unless (fboundp symbol)
  11568.           (error #+DEUTSCH "Funktion ~S ist undefiniert."
  11569.                  #+ENGLISH "Undefined function ~S"
  11570.                  name
  11571.         ) )
  11572.         (if (setq definition (get symbol 'sys::traced-definition))
  11573.           (setq trace-flag t)
  11574.           (setq definition (symbol-function symbol))
  11575.         )
  11576.         (when (and (consp definition) (eq (car definition) 'system::macro))
  11577.           (setq macro-flag t)
  11578.           (setq definition (cdr definition))
  11579.         )
  11580.         (when (compiled-function-p definition)
  11581.           (warn #+DEUTSCH "~S ist schon compiliert."
  11582.                 #+ENGLISH "~S is already compiled."
  11583.                 name
  11584.           )
  11585.           (return-from compile name)
  11586.     ) ) )
  11587.     (unless (or (and (consp definition) (eq (car definition) 'lambda))
  11588.                 (sys::closurep definition)
  11589.             )
  11590.       (error #+DEUTSCH "Das ist weder ein Lambda-Ausdruck noch ein funktionales Objekt:~%~S"
  11591.              #+ENGLISH "Not a lambda expression nor a function: ~S"
  11592.              definition
  11593.     ) )
  11594.     (let ((*compiling* t)
  11595.           (*error-count* 0)
  11596.           (*warning-count* 0)
  11597.           (*compiling-from-file* nil)
  11598.           (*c-listing-output* nil)
  11599.           (*c-error-output* *error-output*)
  11600.           (*known-special-vars* '())
  11601.           (*constant-special-vars* '())
  11602.           (*func* nil)
  11603.           (*fenv* (if (sys::closurep definition)
  11604.                     (sys::%record-ref definition 5)
  11605.                     nil
  11606.           )       )
  11607.           (*benv* (if (sys::closurep definition)
  11608.                     (sys::%record-ref definition 6)
  11609.                     nil
  11610.           )       )
  11611.           (*genv* (if (sys::closurep definition)
  11612.                     (sys::%record-ref definition 7)
  11613.                     nil
  11614.           )       )
  11615.           (*venv* (if (sys::closurep definition)
  11616.                     (sys::%record-ref definition 4)
  11617.                     nil
  11618.           )       )
  11619.           (*venvc* nil)
  11620.           (*denv* (if (sys::closurep definition)
  11621.                     (sys::%record-ref definition 8)
  11622.                     *toplevel-denv*
  11623.           )       )
  11624.           (*no-code* nil))
  11625.       (let ((lambdabody (if (sys::closurep definition)
  11626.                           (sys::%record-ref definition 1)
  11627.                           (cdr definition)
  11628.            ))           )
  11629.         (let ((funobj (compile-lambdabody name lambdabody)))
  11630.           (unless (zerop *error-count*) (return-from compile nil))
  11631.           (if name
  11632.             (progn
  11633.               (when macro-flag (setq funobj (cons 'system::macro funobj)))
  11634.               (if trace-flag
  11635.                 (setf (get symbol 'sys::traced-definition) funobj)
  11636.                 (setf (symbol-function symbol) funobj)
  11637.               )
  11638.               name
  11639.             )
  11640.             funobj
  11641. ) ) ) ) ) )
  11642.  
  11643. ; Top-Level-Formen müssen einzeln aufs .fas-File rausgeschrieben werden,
  11644. ; wegen der Semantik von EVAL-WHEN und LOAD-TIME-VALUE.
  11645. ; Da Top-Level-Formen bei EVAL-WHEN, PROGN und LOCALLY auseinandergebrochen
  11646. ; werden können, muß man LET () verwenden, wenn man dies umgehen will.
  11647.  
  11648. ; Compiliert eine Top-Level-Form für COMPILE-FILE. Der *toplevel-name* wird
  11649. ; meist unverändert durchgereicht. *toplevel-for-value* gibt an, ob der Wert
  11650. ; gebraucht wird (für LOAD :PRINT T) oder nicht.
  11651. (defvar *toplevel-for-value*)
  11652. (defun compile-toplevel-form (form &optional (*toplevel-name* *toplevel-name*))
  11653.   (declare (special *toplevel-name*))
  11654.   (catch 'c-error
  11655.     ; CLtL2 S. 90: "Processing of top-level forms in the file compiler ..."
  11656.     ; 1. Schritt: Macroexpandieren
  11657.     (if (atom form)
  11658.       (when (symbolp form)
  11659.         (let ((h (venv-search-macro form *venv*)))
  11660.           (when (symbol-macro-p h) ; Symbol-Macro ?
  11661.             (return-from compile-toplevel-form
  11662.               (compile-toplevel-form (sys::%record-ref h 0)) ; -> expandieren
  11663.       ) ) ) )
  11664.       (let ((fun (first form)))
  11665.         (when (symbolp fun)
  11666.           (multiple-value-bind (a b c) (fenv-search fun)
  11667.             (declare (ignore b c))
  11668.             (if (null a)
  11669.               ; nicht lokal definiert
  11670.               (case fun
  11671.                 (PROGN ; vgl. c-PROGN
  11672.                   (test-list form 1)
  11673.                   (let ((L (cdr form))) ; Liste der Formen
  11674.                     (cond ((null L) (compile-toplevel-form 'NIL)) ; keine Form
  11675.                           ((null (cdr L)) (compile-toplevel-form (car L))) ; genau eine Form
  11676.                           (t (let ((subform-count 0))
  11677.                                (do ((Lr L))
  11678.                                    ((null Lr))
  11679.                                  (let* ((subform (pop Lr))
  11680.                                         (*toplevel-for-value* (and *toplevel-for-value* (null Lr))))
  11681.                                    (compile-toplevel-form subform
  11682.                                      (symbol-suffix *toplevel-name* (incf subform-count))
  11683.                   ) )     )  ) ) ) )
  11684.                   (return-from compile-toplevel-form)
  11685.                 )
  11686.                 ((LOCALLY EVAL-WHEN COMPILER-LET MACROLET SYMBOL-MACROLET)
  11687.                   (let ((*form* form))
  11688.                     ; c-LOCALLY bzw. c-EVAL-WHEN bzw. c-COMPILER-LET bzw.
  11689.                     ; c-MACROLET bzw. c-SYMBOL-MACROLET aufrufen:
  11690.                     (funcall (gethash fun c-form-table) #'compile-toplevel-form)
  11691.                   )
  11692.                   (return-from compile-toplevel-form)
  11693.                 )
  11694.                 (t (when (macro-function fun) ; globaler Macro ?
  11695.                      (return-from compile-toplevel-form
  11696.                        (compile-toplevel-form (macroexpand-1 form (vector *venv* *fenv*))) ; -> expandieren
  11697.               ) )  ) )
  11698.               ; lokal definiert
  11699.               (when (eq a 'SYSTEM::MACRO) ; lokaler Macro
  11700.                 (return-from compile-toplevel-form
  11701.                   (compile-toplevel-form (macroexpand-1 form (vector *venv* *fenv*))) ; -> expandieren
  11702.               ) )
  11703.     ) ) ) ) )
  11704.     ; 2. Schritt: compilieren und rausschreiben
  11705.     (when (and (not *toplevel-for-value*) (c-constantp form))
  11706.       (return-from compile-toplevel-form)
  11707.     )
  11708.     (let ((*package-tasks* '()))
  11709.       (setq form
  11710.         (compile-lambdabody *toplevel-name*
  11711.           `(() ,form ,@(if *toplevel-for-value* '() '((VALUES)) ) )
  11712.       ) )
  11713.       (when *c-listing-output*
  11714.         (disassemble-closures form *c-listing-output*)
  11715.       )
  11716.       (when *fasoutput-stream*
  11717.         (terpri *fasoutput-stream*)
  11718.         (write form :stream *fasoutput-stream* :pretty t
  11719.                     :closure t :circle t :array t :gensym t
  11720.                     :escape t :level nil :length nil :radix t
  11721.       ) )
  11722.       (when *package-tasks*
  11723.         (c-eval-when-compile `(PROGN ,@(nreverse *package-tasks*)))
  11724.       )
  11725. ) ) )
  11726.  
  11727. ; Common-Lisp-Funktion COMPILE-FILE
  11728. ; file          sollte ein Pathname/String/Symbol sein.
  11729. ; :output-file  sollte nil oder t oder ein Pathname/String/Symbol oder
  11730. ;               ein Output-Stream sein. Default: t.
  11731. ; :listing      sollte nil oder t oder ein Pathname/String/Symbol oder
  11732. ;               ein Output-Stream sein. Default: nil.
  11733. ; :warnings     gibt an, ob die Warnings auch auf dem Bildschirm erscheinen
  11734. ;               sollen.
  11735. ; :verbose      gibt an, ob die Errors auch auf dem Bildschirm erscheinen
  11736. ;               sollen.
  11737. (defun compile-file (file &key (output-file 'T) listing
  11738.                                ((:warnings *compile-warnings*) *compile-warnings*)
  11739.                                ((:verbose *compile-verbose*) *compile-verbose*)
  11740.                           &aux (top-call nil) liboutput-file
  11741.                                (new-output-stream nil) (new-listing-stream nil)
  11742.                     )
  11743.   (setq file (or (first (search-file file '(#".lsp")))
  11744.                  (merge-pathnames file (merge-pathnames '#".lsp"))
  11745.   )          )
  11746.   (when (and output-file (not (streamp output-file)))
  11747.     (setq output-file (if (eq output-file 'T)
  11748.                         (merge-pathnames '#".fas" file)
  11749.                         (merge-pathnames output-file)
  11750.     )                 )
  11751.     (setq liboutput-file (merge-pathnames '#".lib" output-file))
  11752.     (setq new-output-stream t)
  11753.   )
  11754.   (when (and listing (not (streamp listing)))
  11755.     (setq listing (if (eq listing 'T)
  11756.                     (merge-pathnames '#".lis" file)
  11757.                     (merge-pathnames listing)
  11758.     )             )
  11759.     (setq new-listing-stream t)
  11760.   )
  11761.   (with-open-file (istream file :direction :input-immutable)
  11762.     (let ((listing-stream (if new-listing-stream
  11763.                             (open listing :direction :output)
  11764.                             (if (streamp listing) listing nil)
  11765.          ))               ) ; ein Stream oder NIL
  11766.       (unwind-protect
  11767.         (let ((*fasoutput-stream* (if new-output-stream
  11768.                                     (open output-file :direction :output)
  11769.                                     (if (streamp output-file) output-file nil)
  11770.               )                   ) ; ein Stream oder NIL
  11771.               (*liboutput-stream* (if new-output-stream
  11772.                                     (open liboutput-file :direction :output)
  11773.                                     nil
  11774.               )                   ) ; ein Stream oder NIL
  11775.               (compilation-successful nil))
  11776.           (unwind-protect
  11777.             (progn
  11778.               (when listing-stream
  11779.                 (format listing-stream
  11780.                   #+DEUTSCH "~&Listing der Compilation von File ~A~%am ~@? durch ~A in der Version ~A"
  11781.                   #+ENGLISH "~&Listing of compilation of file ~A~%on ~@? by ~A, version ~A"
  11782.                   file
  11783.                   *date-format*
  11784.                   (multiple-value-list (get-decoded-time))
  11785.                     ; Liste (sec min hour day month year ...)
  11786.                   (lisp-implementation-type) (lisp-implementation-version)
  11787.               ) )
  11788.               (unless *compiling* ; Variablen setzen, nicht binden!
  11789.                 (setq *functions-with-errors* '())
  11790.                 (setq *known-special-vars* '()) (setq *unknown-free-vars* '())
  11791.                 (setq *constant-special-vars* '())
  11792.                 (setq *known-functions* '()) (setq *unknown-functions* '())
  11793.                 (setq *inline-functions* '()) (setq *notinline-functions* '())
  11794.                 (setq *inline-definitions* '())
  11795.                 (setq *user-declaration-types* '())
  11796.                 (setq *compiled-modules* '())
  11797.                 (setq top-call t)
  11798.               )
  11799.               (let ((*compiling* t)
  11800.                     (*compiling-from-file* t)
  11801.                     (*package* *package*)
  11802.                     (*readtable* *readtable*)
  11803.                     (*c-listing-output* listing-stream)
  11804.                     (*c-error-output*
  11805.                       (if listing-stream
  11806.                         (make-broadcast-stream *error-output* listing-stream)
  11807.                         *error-output*
  11808.                     ) )
  11809.                     (*func* nil)
  11810.                     (*fenv* nil)
  11811.                     (*benv* nil)
  11812.                     (*genv* nil)
  11813.                     (*venv* nil)
  11814.                     (*venvc* nil)
  11815.                     (*denv* *toplevel-denv*)
  11816.                     (*error-count* 0) (*warning-count* 0)
  11817.                     (*no-code* (and (null *fasoutput-stream*) (null listing-stream)))
  11818.                     (*toplevel-for-value* t)
  11819.                     (eof-value "EOF")
  11820.                     (form-count 0)
  11821.                    )
  11822.                 (c-comment #+DEUTSCH "~%File ~A wird compiliert..."
  11823.                            #+ENGLISH "~%Compiling file ~A ..."
  11824.                            file
  11825.                 )
  11826.                 (when *fasoutput-stream*
  11827.                   (let ((*package* *keyword-package*))
  11828.                     (write `(SYSTEM::VERSION ',(version)) :stream *fasoutput-stream*
  11829.                            :escape t :level nil :length nil :radix t
  11830.                 ) ) )
  11831.                 (loop
  11832.                   (let ((form (read istream nil eof-value)))
  11833.                     (when (eql form eof-value) (return))
  11834.                     (compile-toplevel-form form
  11835.                       (symbol-suffix '#:TOP-LEVEL-FORM (incf form-count))
  11836.                 ) ) )
  11837.                 (c-comment #+DEUTSCH "~&~%Compilation von File ~A beendet."
  11838.                            #+ENGLISH "~&~%Compilation of file ~A is finished."
  11839.                            file
  11840.                 )
  11841.                 (c-comment #+DEUTSCH "~%~D Error~:P, ~D Warnung~:[en~;~]"
  11842.                            #+ENGLISH "~%~D error~:P, ~D warning~:P"
  11843.                            *error-count* *warning-count* #-ENGLISH (eql *warning-count* 1)
  11844.                 )
  11845.                 (when top-call
  11846.                   (when *functions-with-errors*
  11847.                     (c-comment #+DEUTSCH "~%Es gab Errors in den folgenden Funktionen:~%~{~<~%~:; ~S~>~^~}"
  11848.                                #+ENGLISH "~%There were errors in the following functions:~%~{~<~%~:; ~S~>~^~}"
  11849.                                (nreverse *functions-with-errors*)
  11850.                   ) )
  11851.                   (setq *unknown-functions*
  11852.                     (nset-difference *unknown-functions* *known-functions* :test #'equal)
  11853.                   )
  11854.                   (when *unknown-functions*
  11855.                     (c-comment #+DEUTSCH "~%Folgende Funktionen wurden verwendet, aber nicht definiert:~%~{~<~%~:; ~S~>~^~}"
  11856.                                #+ENGLISH "~%The following functions were used but not defined:~%~{~<~%~:; ~S~>~^~}"
  11857.                                (nreverse *unknown-functions*)
  11858.                   ) )
  11859.                   (let ((unknown-vars (set-difference *unknown-free-vars* *known-special-vars*))
  11860.                         (too-late-vars (intersection *unknown-free-vars* *known-special-vars*)))
  11861.                     (when unknown-vars
  11862.                       (c-comment #+DEUTSCH "~%Folgende Special-Variablen wurden nicht definiert:~%~{~<~%~:; ~S~>~^~}"
  11863.                                  #+ENGLISH "~%The following special variables were not defined:~%~{~<~%~:; ~S~>~^~}"
  11864.                                  (nreverse unknown-vars)
  11865.                     ) )
  11866.                     (when too-late-vars
  11867.                       (c-comment #+DEUTSCH "~%Folgende Special-Variablen wurden zu spät definiert:~%~{~<~%~:; ~S~>~^~}"
  11868.                                  #+ENGLISH "~%The following special variables were defined too late:~%~{~<~%~:; ~S~>~^~}"
  11869.                                  (nreverse too-late-vars)
  11870.                 ) ) ) )
  11871.                 (c-comment "~%")
  11872.                 (setq compilation-successful
  11873.                   (zerop *error-count*) ; Wert T, falls Compilation erfolgreich
  11874.             ) ) )
  11875.             (when new-output-stream
  11876.               (close *fasoutput-stream*) (close *liboutput-stream*)
  11877.               (unless compilation-successful
  11878.                 (delete-file output-file) (delete-file liboutput-file)
  11879.             ) )
  11880.         ) )
  11881.         (when new-listing-stream (close listing-stream))
  11882. ) ) ) )
  11883.  
  11884. (defun disassemble-closures (closure stream)
  11885.   (let ((closures '()))
  11886.     (labels ((mark (cl) ; trägt eine Closure cl (rekursiv) in closures ein.
  11887.                (push cl closures) ; cl markieren
  11888.                (dolist (c (closure-consts cl)) ; und alle Teil-Closures
  11889.                  (when #+CLISP (and (sys::closurep c) (compiled-function-p c))
  11890.                        #-CLISP (closure-p c)
  11891.                    (unless (member c closures) (mark c)) ; ebenfalls markieren
  11892.             )) ) )
  11893.       (mark closure) ; Haupt-Closure markieren
  11894.     )
  11895.     (dolist (c (nreverse closures)) ; alle Closures disassemblieren
  11896.       (disassemble-closure c stream)
  11897. ) ) )
  11898.  
  11899. #-CLISP
  11900. (defun disassemble-closure (closure &optional (stream *standard-output*))
  11901.   (format stream #+DEUTSCH "~%~%Disassembly von Funktion ~S"
  11902.                  #+ENGLISH "~%~%Disassembly of function ~S"
  11903.                  (closure-name closure)
  11904.   )
  11905.   (multiple-value-bind (req-anz opt-anz rest-p key-p keyword-list allow-other-keys-p
  11906.                         byte-list const-list)
  11907.       (signature closure)
  11908.     (do ((L const-list (cdr L))
  11909.          (i 0 (1+ i)))
  11910.         ((null L))
  11911.       (format stream "~%(CONST ~S) = ~S" i (car L))
  11912.     )
  11913.     (format stream #+DEUTSCH "~%~S notwendige Argumente"
  11914.                    #+ENGLISH "~%~S required arguments"
  11915.                    req-anz
  11916.     )
  11917.     (format stream #+DEUTSCH "~%~S optionale Argumente"
  11918.                    #+ENGLISH "~%~S optional arguments"
  11919.                    opt-anz
  11920.     )
  11921.     (format stream #+DEUTSCH "~%~:[Kein Rest-Parameter~;Rest-Parameter vorhanden~]"
  11922.                    #+ENGLISH "~%~:[No rest parameter~;Rest parameter~]"
  11923.                    rest-p
  11924.     )
  11925.     (if key-p
  11926.       (let ((kw-count (length keyword-list)))
  11927.         (format stream #+DEUTSCH "~%~S Keyword-Parameter: ~{~S~^, ~}."
  11928.                        #+ENGLISH "~%~S keyword parameter~:P: ~{~S~^, ~}."
  11929.                        kw-count keyword-list
  11930.         )
  11931.         (when allow-other-keys-p
  11932.           (format stream #+DEUTSCH "~%Andere Keywords sind zugelassen."
  11933.                          #+ENGLISH "~%Other keywords are allowed."
  11934.       ) ) )
  11935.       (format stream #+DEUTSCH "~%Keine Keyword-Parameter"
  11936.                      #+ENGLISH "~%No keyword parameters"
  11937.     ) )
  11938.     (let ((const-string-list (mapcar #'write-to-string const-list)))
  11939.       (do ((L (disassemble-LAP byte-list const-list) (cdr L)))
  11940.           ((null L))
  11941.         (let ((PC (caar L))
  11942.               (instr (cdar L)))
  11943.           (format stream "~%~S~6T~A" PC instr)
  11944.           (multiple-value-bind ... ; siehe unten
  11945.             ...
  11946.     ) ) ) )
  11947.     (format stream "~%")
  11948. ) )
  11949. #+CLISP
  11950. (defun disassemble-closure (closure &optional (stream *standard-output*))
  11951.   (terpri stream)
  11952.   (terpri stream)
  11953.   (write-string #+DEUTSCH "Disassembly von Funktion "
  11954.                 #+ENGLISH "Disassembly of function "
  11955.                 stream
  11956.   )
  11957.   (prin1 (closure-name closure) stream)
  11958.   (multiple-value-bind (req-anz opt-anz rest-p key-p keyword-list allow-other-keys-p
  11959.                         byte-list const-list)
  11960.       (signature closure)
  11961.     (do ((L const-list (cdr L))
  11962.          (i 0 (1+ i)))
  11963.         ((null L))
  11964.       (terpri stream)
  11965.       (write-string "(CONST " stream)
  11966.       (prin1 i stream)
  11967.       (write-string ") = " stream)
  11968.       (prin1 (car L) stream)
  11969.     )
  11970.     (terpri stream)
  11971.     (prin1 req-anz stream)
  11972.     (write-string #+DEUTSCH " notwendige Argumente"
  11973.                   #+ENGLISH " required arguments"
  11974.                   stream
  11975.     )
  11976.     (terpri stream)
  11977.     (prin1 opt-anz stream)
  11978.     (write-string #+DEUTSCH " optionale Argumente"
  11979.                   #+ENGLISH " optional arguments"
  11980.                   stream
  11981.     )
  11982.     (terpri stream)
  11983.     (if rest-p
  11984.       (write-string #+DEUTSCH "Rest-Parameter vorhanden"
  11985.                     #+ENGLISH "Rest parameter"
  11986.                     stream
  11987.       )
  11988.       (write-string #+DEUTSCH "Kein Rest-Parameter"
  11989.                     #+ENGLISH "No rest parameter"
  11990.                     stream
  11991.     ) )
  11992.     (if key-p
  11993.       (let ((kw-count (length keyword-list)))
  11994.         (terpri stream)
  11995.         (prin1 kw-count stream)
  11996.         #+DEUTSCH (write-string " Keyword-Parameter: " stream)
  11997.         #+ENGLISH (progn
  11998.                     (write-string " keyword parameter" stream)
  11999.                     (unless (eql kw-count 1) (write-string "s" stream))
  12000.                     (write-string ": " stream)
  12001.                   )
  12002.         (do ((L keyword-list))
  12003.             ((endp L))
  12004.           (prin1 (pop L) stream)
  12005.           (if (endp L) (write-string "." stream) (write-string ", " stream))
  12006.         )
  12007.         (when allow-other-keys-p
  12008.           (terpri stream)
  12009.           (write-string #+DEUTSCH "Andere Keywords sind zugelassen."
  12010.                         #+ENGLISH "Other keywords are allowed."
  12011.                         stream
  12012.       ) ) )
  12013.       (progn
  12014.         (terpri stream)
  12015.         (write-string #+DEUTSCH "Keine Keyword-Parameter"
  12016.                       #+ENGLISH "No keyword parameters"
  12017.                       stream
  12018.     ) ) )
  12019.     (let ((const-string-list
  12020.             (mapcar #'(lambda (x) (sys::write-to-short-string x 35)) const-list)
  12021.          ))
  12022.       (do ((L (disassemble-LAP byte-list const-list) (cdr L)))
  12023.           ((null L))
  12024.         (let ((PC (caar L))
  12025.               (instr (cdar L)))
  12026.           (terpri stream)
  12027.           (prin1 PC stream)
  12028.           (dotimes (i (- 6 (sys::line-position stream))) (write-char #\Space stream)) ; Tab 6
  12029.           (princ instr stream) ; instr ausgeben, Symbole ohne Package-Marker!
  12030.           (multiple-value-bind (commentp comment)
  12031.             (when (consp instr)
  12032.               (case (first instr)
  12033.                 ((CALLS1 CALLS1&PUSH CALLS1&STORE CALLS1&JMPIFNOT CALLS1&JMPIF)
  12034.                   (values t (%funtabref (second instr)))
  12035.                 )
  12036.                 ((CALLS2 CALLS2&PUSH CALLS2&STORE CALLS2&JMPIFNOT CALLS2&JMPIF)
  12037.                   (values t (%funtabref (+ 256 (second instr))))
  12038.                 )
  12039.                 ((CALLSR CALLSR&PUSH CALLSR&STORE CALLSR&JMPIFNOT CALLSR&JMPIF)
  12040.                   (values t (%funtabref (+ funtabR-index (third instr))))
  12041.                 )
  12042.                 ((CALL CALL&PUSH)
  12043.                   (values 'string (nth (third instr) const-string-list))
  12044.                 )
  12045.                 ((CALL0 CALL1 CALL1&PUSH CALL1&JMPIFNOT CALL1&JMPIF
  12046.                   CALL2 CALL2&PUSH CALL2&JMPIFNOT CALL2&JMPIF
  12047.                   JMPIFEQTO JMPIFNOTEQTO CONST CONST&PUSH SETVALUE GETVALUE
  12048.                   GETVALUE&PUSH BIND CONST&STORE CONST&SYMBOL-FUNCTION&PUSH
  12049.                   CONST&SYMBOL-FUNCTION COPY-CLOSURE&PUSH COPY-CLOSURE
  12050.                   CONST&SYMBOL-FUNCTION&STORE
  12051.                  )
  12052.                   (values 'string (nth (second instr) const-string-list))
  12053.             ) ) )
  12054.             (when commentp
  12055.               (dotimes (i (max 1 (- 42 (sys::line-position stream)))) (write-char #\Space stream)) ; Tab 42
  12056.               (write-string "; " stream)
  12057.               (if (eq commentp 'string)
  12058.                 (write-string comment stream)
  12059.                 (prin1 comment stream)
  12060.     ) ) ) ) ) )
  12061.     (terpri stream)
  12062. ) )
  12063.  
  12064. #-CROSS
  12065. (defun disassemble (object &aux name)
  12066.   (when (function-name-p object)
  12067.     (unless (fboundp object)
  12068.       (error #+DEUTSCH "Funktion ~S ist undefiniert."
  12069.              #+ENGLISH "Undefined function ~S"
  12070.              object
  12071.     ) )
  12072.     (setq name object)
  12073.     (setq object (get-funname-symbol object))
  12074.     (setq object (or (get object 'sys::traced-definition)
  12075.                      (symbol-function object)
  12076.   ) )            )
  12077.   (when (and (consp object) (eq (car object) 'system::macro))
  12078.     (setq object (cdr object))
  12079.   )
  12080.   (unless (sys::closurep object)
  12081.     (error #+DEUTSCH "~S kann nicht disassembliert werden."
  12082.            #+ENGLISH "Cannot disassemble ~S"
  12083.            object
  12084.   ) )
  12085.   ; object ist eine Closure.
  12086.   (unless (compiled-function-p object)
  12087.     (setq object
  12088.       (compile-lambda (sys::%record-ref object 0) ; name
  12089.                       (sys::%record-ref object 1) ; lambdabody
  12090.                       (sys::%record-ref object 4) ; venv
  12091.                       (sys::%record-ref object 5) ; fenv
  12092.                       (sys::%record-ref object 6) ; benv
  12093.                       (sys::%record-ref object 7) ; genv
  12094.                       (sys::%record-ref object 8) ; denv
  12095.   ) ) )
  12096.   ; object ist eine compilierte Closure.
  12097.   (disassemble-closure object) ; Disassemblieren
  12098.   object ; compilierte Closure als Wert
  12099. )
  12100.